1. 角谷猜想
(kakutani.pas/c/cpp)
(kakutani.in/out)
时间限制:1s/空间限制:256M
【题目描述】
    某个名字末尾是 654321 的小 A 同学是个大家眼中公认的学霸(虽然他永远
  不承认),他对题目的直觉到了一种可怕的地步,一眼看出题目的算法对他而言
  只是小 Case,他甚至能在看到一个证明的瞬间敏锐地判断出这个证明的真伪。
  现在小 A 同学机缘巧合地看到了角古猜想 (即对于 x 当它为奇数则 1 3   x x ,
  为偶数,则
  2
  x
  x  ,一直重复这个步骤,则 x 最终会变为 1),在看完这个猜想的
   一瞬间,他的直觉就来了——他认为角古猜想一定是错的!然后——他立刻就能
  找出反例!
    他立刻在纸上写满了 ) 00 10 1 (   n n 个小于 ) 10 0 ( 10
  4
    L
  L
  的正整数, 打算放
  到他的 grand super computer 上去跑,可是他突然觉得有些正整数不是很吉利,
  可能会干扰到他的最终结果,所以他打算把一些正整数加工一下。
    小 A 觉得 4、7、13 都是不吉利的数字,所以要把所有正整数里的 4、7、13
  都去掉,如果去掉后得到的新数字里依旧有 4、7、13,那么就要继续删掉,直
  到最后的数组不存在 4、7、13,它才是一个吉利的数字。
    例如 1 => 113 => 11133 => 111733 => 1411733
    特别规定,如果最后所有数字都被删掉了,就输出 0
    小A觉得这个枯燥的工作不适合他这样的天才, 于是就把这个工作交给了你。
  当然, 只要你能顺利解决,小 A 承诺会在那篇将会震惊世界的论文的特别感谢栏
  上署上你的大名。
【输入格式】 (kakutani.in)
  一共 1  n 行。
  第一行一个正整数 ) 0 10 1 (   n n ,表示数字个数。
  接下来每行一个正整数 x 。
【输出格式】 (kakutani.out)
  一共 n 行。
  每行一个正整数,表示输入每个 x 对应的答案。
【输入输出样例】
  kakutani.in kakutani.out
  5
  13713
  141713
  1333333372589
  1411733
  2147483647
  0
  11
  3333332589
  1
  21836
【数据规模约定】
  对于 10% 的数据, 2147483647 0   x
  对于另外 10% 的数据,给定的数字 x 没有数码 3
  对于另外 10% 的数据, 1  n
  对于全部的数据, ) 00 10 1 (   n n ,
Lx 10 1   )

 思路:栈维护一下。

 吐槽:学校的机子跑的太慢了,竟然卡我输出。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,bns[],vis[];
char num[];
int main(){
freopen("kakutani.in","r",stdin);
freopen("kakutani.out","w",stdout);
scanf("%d",&n);
while(n--){
scanf("%s",num);
int len=strlen(num),pos=,ff=;
memset(vis,,sizeof(vis));
for(int i=;i<len;i++){
if(num[i]=='') vis[i]=;
else if(num[i]=='') vis[i]=;
else if(num[i]=='') bns[++pos]=i;
else if(num[i]==''&&pos){
vis[i]=;
vis[bns[pos--]]=;
}
else pos=;
}
for(int i=;i<len;i++)
if(!vis[i]){
ff=;
putchar(num[i]);
}
if(!ff) putchar('');
printf("\n");
}
}
/*
4
123131313473
*/

2. 刀塔
(dota.pas/c/cpp)
(dota.in/out)
时间限制:2s/空间限制:256M
【题目描述】
    事情要从小 A 的朋友小 S 说起,小 S 是个刀塔狂热粉,他每天除了学习就是
  在打刀塔。然而让小 S 很苦恼的事情是,他发现最近他似乎遇见瓶颈了,他发现
  他每次输的时候都是雪崩, 赢的时候都是躺赢, 完全发挥不出自己应该有的实力。
  他上贴吧请教了三分钟辉耀羊刀的万分大神,接到了万分大神的圣旨:去看自己
  的录像反省反省。于是小 S 决定利用十一假期的时间好好反省反省。
    小 S 调出了自己前段时间的游戏录像,一共有 N 个录像,他给每个录像一个
  正整数表示这个录像的观看价值。 现在他决定从里面找到二组连续的录像来观看,
  这两组录像的要求如下:
    1.两组录像里每一组的录像数量都不能小于 A,不然没有意义
    2.他看的总录象的数量一定要超过 B,他相信看的越多就越好
    3.小 S 觉得两组录像时间隔的太近没有意义,因为很有可能前后两段暴露的
    问题基本一致,但是他又觉得隔的太远也干扰他去思考自己当时的状态。所以他
  要求这两段录像中间应该刚好隔了 K 个录像
    好吧,这已经够让人烦躁的了,但是小 S 还不满足,他觉得这样的挑选方案
  依旧很多,所以他想挑选足够好的方案,一个质量足够高的方案——也就是观看
  价值最低的录像的观看价值要尽可能的高。
【输入格式】 (dota.in)
  一共 2 行。
  第一行四个正整数 K B A N 、 、 、 。
  接下来一行 N 个正整数,表示每个录像的观看价值 ) 10 1 (
  9
    x x 。
【输出格式】 (dota.out)
  一共 1 行,表示最佳方案中观看价值最低的录像的观看价值。
【输入输出样例 1】
  dota.in dota.out
  10 2 5 3
  7 8 2 3 1 6 4 10 5 9
  4
【输入输出样例 2】
  dota.in dota.out
  20 3 9 3
  54867025 259306632 473619223 170507035
  347936959 421059860 246006182 948910354
  630205869 541359081 574152766 665959900
  843439075 445125437 774018043 719562887
  705993886 133173428 256457367 708196876
  246006182
【数据规模约定】
  保证 B A A   , N K B  
  对于 10% 的数据, 1000 100   N
  对于另外 10% 的数据, B A A  
  对于另外 30% 的数据, 100  B
  对于全部的数据, ) 10 100 (
  6
    N N , 0 000 10 10   K B,
【样例解释】
  对于样例 1,最优方案为选择 7 8 2 3 1 6 4 10

40分暴力

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000010
using namespace std;
int x,y;
int asd,qwq;
int A,B,k,ans;
int t,q,n,mx,nm;
int a[N];
int stmin[N][],mn[N];
void init(){
mn[]=-;
for(int i=;i<=n;i++){
mn[i]=((i&(i-))==)?mn[i-]+:mn[i-];
stmin[i][]=a[i];
}
for(int j=;j<=mn[n];j++)
for(int i=;i+(<<j)-<=n;i++)
stmin[i][j]=min(stmin[i][j-],stmin[i+(<<(j-))][j-]);
}
int rmq_min(int L,int R){
int k=mn[R-L+];
return min(stmin[L][k],stmin[R-(<<k)+][k]);
}
int main(){
freopen("dota.in","r",stdin);
freopen("dota.out","w",stdout);
scanf("%d%d%d%d",&n,&A,&B,&k);
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
init();
for(int i=;i<=n-B-k+;i++){
mx=B-A;
for(int j=A;j<=mx;j++){
nm=B-j;
asd=rmq_min(i,i+j-);
qwq=rmq_min(i+j+k,i+j+k+nm-);
ans=max(ans,min(asd,qwq));
}
}
cout<<ans;
}

正解思路:

以下解题思路来自xxy大佬的博客

枚举i为间隔K个录像的左端点,那么间隔录像为[i,i+k-1]

设第一段为[Sa,Ta],第二段为[Sb,Tb],Ma为min[Sa,Ta],Mb为min[Sb,Tb]

随着Sa的左移,Ma单调不增

随着Tb的右移,Mb单调不增

如果枚举Sa,则有以下式子: Ta-Sa+1+Tb-Sb+1>=B

即Tb>=B+Sa+Sb-Ta-2

因为Tb右移,Mb单调不增,所以Tb取等号最优

所以二分Sa的位置,用st表查询Ma,Mb

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 1000001
using namespace std;
int n,p,k,A,B;
int logg2[MAXN];
int st[MAXN][];
void stpre(){
p=log2(n);
for(int j=,k=;j<=p;j++,k<<=)
for(int i=;i+k-<=n;i++)
st[i][j]=min(st[i][j-],st[i+(k>>)][j-]);
for(int i=;i<=n;i++) logg2[i]=log2(i);
}
int getmin(int s,int t){
p=logg2[t-s+];
int len=<<p;
return min(st[s][p],st[t-len+][p]);
}
int main(){
freopen("dota.in","r",stdin);
freopen("dota.out","w",stdout);
scanf("%d%d%d%d",&n,&A,&B,&k);
for(int i=;i<=n;i++)
scanf("%d",&st[i][]);
stpre();
int Sa,Sb,Ta,Tb,Ma,Mb,Mi;
int ans=;
int l,r,mid,tmp;
for(int i=A+;i<=n-A-k+;i++){
Ta=i-;
Sb=i+k;
Tb=max(Sb+A-,B+i-A+Sb-Ta-);
Ma=getmin(i-A,Ta);
Mb=getmin(Sb,Tb);
l=;r=i-A;tmp=min(Ma,Mb);
while(l<=r){
mid=(l+r)/;
Tb=max(Sb+A-,B+mid+Sb-Ta-);
Ma=getmin(mid,Ta);
Mb=getmin(Sb,Tb);
tmp=max(tmp,min(Ma,Mb));
if(Ma<Mb) l=mid+;
else if(Ma==Mb) break;
else r=mid-;
}
ans=max(ans,tmp);
}
printf("%d",ans);
}

3. 反击数
(spenum.pas/c/cpp)
(spenum.in/out)
时间限制:2s/空间限制:256MB
【题目描述】
    上次说到小 A 在你的帮助下,在反证角谷猜想的路上已经看见了曙光,他相
  信自己即将为这个著名难题画上最后的句点,小 A 十分地兴奋,结果他那微不足
  道的老毛病又犯了——他忍不住想炫耀一番,结果搞得朋友圈内人尽皆知,当然
  也就传到了另一位学霸小 H 的耳中。
    虽然表面上小 H 和小 A 是挚友,但其实不难想象,这两个天才在私下里早已
  将对方视为此生必须要战胜的对手。和天赋异禀的小 A 不同,小 H 拥有的是逆天
  的气运——经常他选择题都不需要看选项就能全对 (据说这也是曾经笃信唯物主
  义的小 A 为什么变得神经质般迷信的根本原因) 现在小 H 要正式向小 A 在角谷猜
  想上发起反击, 不过两个学霸在某一点上倒是达成了一致——这个猜想一定是错
  的,所以它必然有反例!
    对自己的气运抱有足够自信的小 H 打算用这样的方式来找到反例:他先选定
   一个自己的幸运数 X,他认为所有中间出现了 X 的数都是“扩展幸运数” (包括
  X 自身) (例:若 X=69 那么 84576901 就是一个“扩展幸运数” ,在 84576 后面
  出现了数码 69,而 679 则不是一个“扩展幸运数” ),然后小 H 会再精心挑选一
  个“命运数”K,最后小 H 将在随机生成的正整数区间[L, R]中选择第 K 大的“扩
  展幸运数” ,用它去验证角谷猜想。小 H 认为这样的速度一定快过小 A 那个落后
  的办法。
    好了,现在同样的工作摆在了你的面前,你需要帮助小 H 得到那个数字。
   PS:小 H 有时候会突然无征兆地打瞌睡(为了保养他的运气) ,所以可能正
  整数区间[L, R]中并没有 K 个“扩展幸运数” ,这时候输出“Hey,wake up!” (不
  含引号)
【输入格式】 (spenum.in)
  输入仅有一行,共 4 个数字,按次序分别为 L,R,X,K
【输出格式】 (spenum.out)
  输出为一行,即正整数区间[L, R]中第 K 大的“扩展幸运数”
【输入输出样例 1】
  spenum.in spenum.out
  1 1000 6 14 67
【输入输出样例 2】
  spenum.in spenum.out
  1 1 2 1 Hey,wake up!
【样例解释】
  前 14 个数字分别是 6、16、26、36、46、56、60、61、62、63、64、65、66、67
【数据规模约定】
  对于 10% 的数据 : 1000000 1    L R
  对于另外 10% 的数据 : 1  K
  对于另外 20% 的数据 : 9 1   X
  对于 100% 的数据 :
  18
  10 , , , 1   K X R L

思路:

数位DP

dp[i][j][0/1] 前i位匹配到X的第j位,是否已经包含1个X的数的个数

二分,计算<=mid的数里的答案

其中的匹配用kmp

这个dp的清空可以只在最开始清空一次。

原因在这里:

第一:memset(dp,-,sizeof dp);放在多组数据外面。

这一点是一个数位特点,使用的条件是:约束条件是每个数自身的属性,而与输入无关。
具体的:上一题不要62和4,这个约束对每一个数都是确定的,就是说任意一个数满不满足这个约束都是确定,比如444这个数,它不满足约束条件,不管你输入的区间是多少你都无法改变这个数不满足约束这个事实,这就是数自身的属性(我们每组数据只是在区间计数而已,只能说你输入的区间不包含444的话,我们就不把它统计在内,而无法改变任何事实)。
由此,我们保存的状态就可以一直用(注意还有要limit,不同区间是会影响数位在有限制条件下的上限的)
这点优化就不给具体题目了,这个还有进一步的扩展。不过说几个我遇到的简单的约束:
.求数位和是10的倍数的个数,这里简化为数位sum%10这个状态,即dp[pos][sum]这里10 是与多组无关的,所以可以memset优化,不过注意如果题目的模是输入的话那就不能这样了。
.求二进制1的数量与0的数量相等的个数,这个也是数自身的属性。
.。。。。。
还是做题积累吧。搞懂思想!
下面介绍的方法就是要行memset优化,把不满足前提的通过修改,然后优化。
介绍之前,先说一种较为笨拙的修改,那就是增加状态,前面讲limit的地方说增加一维dp[pos][state][limit],能把不同情况下状态分别记录(不过这个不能memset放外面)。基于这个思想,我们考虑:约束为数位是p的倍数的个数,其中p数输入的,这和上面sum%10类似,但是dp[pos][sum]显然已经不行了,每次p可能都不一样,为了强行把memset提到外面加状态dp[pos][sum][p],对于每个不同p分别保存对应的状态。这里前提就比较简单了,你dp数组必须合法,p太大就G_G了。所以对于与输入有关的约束都可以强行增加状态(这并不代表能ac,如果题目数据少的话就随便你乱搞了)

或者戳这里

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int len;
char X[];
long long L,R,K;
int net[],num[];
long long l,r,mid,ans;
long long dp[][][];
void KMP(){
len=strlen(X);
int j;
for(int i=;i<len;i++){
j=net[i];
while(j&&X[i]!=X[j]) j=net[j];
net[i+]=X[i]==X[j]?j+:;
}
}
long long dfs(int pos,int stact,bool limite,bool get){
if(pos==-) return get;
if(!limite&&dp[pos][stact][get]!=-) return dp[pos][stact][get];
int up=limite?num[pos]:;
long long tmp=;
int j;
for(int i=;i<=up;i++){
j=stact;
while(j&&X[j]-''!=i) j=net[j];
if(X[j]-''==i) j++;
tmp+=dfs(pos-,j,limite&&(i==up),get||(j==len));
}
if(!limite) dp[pos][stact][get]=tmp;
return tmp;
}
long long slove(long long now){
int pos=;
while(now){
num[pos++]=now%;
now/=;
}
return dfs(pos-,,,);
}
int main(){ freopen("spenum.in","r",stdin);
freopen("spenum.out","w",stdout);
scanf("%I64d%I64d%s%I64d",&L,&R,X,&K);
KMP();
memset(dp,-,sizeof(dp));
long long tmp=slove(L-);
if(slove(R)-slove(L-)<K){
puts("Hey,wake up!");
return ;
}
l=L;r=R;
while(l<=r){
mid=(l+r)/;
if(slove(mid)-tmp<K) l=mid+;
else{
ans=mid;
r=mid-;
}
}
printf("%I64d",ans);
}

最新文章

  1. 只有IE64位能上网。
  2. android架构
  3. 注意,ruby循环体定义的变量在结束时后,变量还存在
  4. mini6410-JNI-led
  5. OO之装饰者模式
  6. Javascript中那些偏门的知识
  7. PHP 类和继承
  8. 安卓天天练练(十五)改造BasicSyncAdapter
  9. VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE)
  10. CSS自学笔记(16):CSS3 用户界面
  11. 【互动问答分享】第15期决胜云计算大数据时代Spark亚太研究院公益大讲堂
  12. C#将image中的显示的图片转换成二进制
  13. Java笔记(三)
  14. Hibernate工具类_抽取重复核心代码
  15. GoLang simple-project-demo-01
  16. python读取uti-8格式ini配置文件出现UnicodeDecodeError: &#39;gbk&#39; codec can&#39;t decode byte 0xba in position 367: illegal multibyte sequence错误解决方法
  17. ssh跳过knownhost文件
  18. linux应用编程之进程间同步
  19. javascript学习笔记(八):浏览器对象
  20. Docker仓库(四)

热门文章

  1. js正则学习小计
  2. mac下maven的安装配置与使用
  3. CSS3-----transform 转换
  4. 运维派 企业面试题4&amp;5 创建10个 用户 ; ping探测主机是否在线
  5. 洛谷 P1462 通往奥格瑞玛的道路 二分 最短路
  6. tinymce原装插件源码分析(二)-link
  7. 比较排序算法(PHP)
  8. scrapy爬取boss直聘实习生数据
  9. linux 安装 redis3.0
  10. hadoop-04-mysql安装