国庆 day 6 上午
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);
}
国庆 day 6 上午的更多相关文章
- 国庆 day 7 上午
思路:模拟,set记录一下. #include<set> #include<cstdio> #include<cstring> #include<iostre ...
- 国庆 day 3 上午
a[问题描述] 你是能看到第一题的 friends 呢. ——hja 怎么快速记单词呢?也许把单词分类再记单词是个不错的选择.何大爷给 出了一种分单词的方法,何大爷认为两个单词是同一类的当这两个单词的 ...
- 国庆 day 2 上午
一道图论神题(god) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有 ...
- 2018国庆YALI集训游记
想了想,像之前那样简略地叙述题意和做法,根本没讲清楚,没有任何意义,还不如写写自己的感受. 感觉YALI真的是一所挺不错的学校吧.总是能有一机房的julao轮番吊打你,总是能有集训队的奆佬来给你出dl ...
- SSH-Struts第三弹:传智播客视频教程第一天上午的笔记
一. 框架概述1.三大框架 : 是企业主流 JavaEE 开发的一套架构 Struts2 + Spring + Hibernate 2. 什么是框架?为什么要学框架 ?框架 是 实现部分功能的代码 ( ...
- JAVA判断当前时间是上午am还是下午pm
//结果为"0"是上午 结果为"1"是下午 public class GregorianTest { public static void main(Strin ...
- PKUSC 模拟赛 day2 上午总结
今天上午考得不是很好,主要还是自己太弱QAQ 开场第一题给的图和题意不符,搞了半天才知道原来是走日字形的 然后BFS即可 #include<cstdio> #include<cstr ...
- PKUSC 模拟赛 day1 上午总结
思考了一下第二题,觉得有无数种乱搞做法 类似什么bitset压位,MCS染色之类奇怪的做法 然而都是玄学正确性或者玄学复杂度 先放题解把 第一题显然具有单调性,二分就可以啦 O(nlogn),貌似输出 ...
- hihoCoder 1041 国庆出游 (DFS)
题意: 小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历 ...
随机推荐
- swift语言点评十六-Initialization && Deinitialization
initial value:必须初始化.不影响观察者 Classes and structures must set all of their stored properties to an appr ...
- swift语言点评十一-Methods
Assigning to self Within a Mutating Method Mutating methods can assign an entirely new instance to t ...
- 优动漫PAINT画树教程
依次解析画树要点!让画树不再是难事~ 优动漫PAINT下载:http://wm.makeding.com/iclk/?zoneid=18597
- 百度蜘蛛IP地址到底代表什么含义?
百度蜘蛛IP地址到底代表什么含义,是不是不同的ip地址所代表的含义不一样呢?对权重和抓取是否有影响?哪些是无效的蜘蛛,哪些是站长工具的蜘蛛,那些又是百度自己真正的蜘蛛?百度蜘蛛,是百度搜索引擎的一个自 ...
- BZOJ 4103 [Thusc 2015]异或运算 (可持久化01Trie+二分)
题目大意:给你一个长方形矩阵,位置$i,j$上的数是$a_{i}\;xor\;b_{j}$,求某个子矩阵内第$K$大的值 最先想的是二分答案然后验证,然而是$O(qnlogmloga_{i})$,不出 ...
- centos7 jumpserver 部署和使用手册(一)
测试推荐环境 CPU: 64位双核处理器 内存: 4G DDR3 数据库:mysql 版本大于等于 5.6 mariadb 版本大于等于 5.5.6 环境 系统: CentOS 7.2 IP: 192 ...
- 记录python之递归函数
函数move(n,a,b,c)的定义是将n个圆盘从a借助b移动到c. def move(n,a,b,c): if n==1: print a,'-->',c move (n-1,a,c,b) p ...
- 紫书 习题8-11 UVa 1615 (区间选点问题)
这个点就是贪心策略中的区间选点问题. 把右端点从大到小排序, 左端点从小到大排序. 每次取区间右端点就可以了, 到不能覆盖的时候就ans++, 重新取点 ps:这道题不考虑精度也可以过 要着重复习一下 ...
- lower_bound与upper_bound
昨天一道题目用了lower_bound,大致了解了lower_bound指的是第一个>=x的位置.但是之前对于upper_bound有误解,其实upper_bound指的是第一个>x的位置 ...
- _stat函数/struct stat 结构体使用笔记
内容来自互联网,非原创,方便以后查看. 另,关于获取文件信息——_stat函数的使用详见 http://blog.csdn.net/frank_liuxing/article/details/1860 ...