2017北京国庆刷题Day6 morning
Posted 日拱一卒 功不唐捐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017北京国庆刷题Day6 morning相关的知识,希望对你有一定的参考价值。
期望得分:100+100+20=220
实际得分:100+100+20=220
模拟栈
#include<cstdio> #include<cstring> using namespace std; #define N 10002 char s[N],st[N]; int top; int main() { freopen("kakutani.in","r",stdin); freopen("kakutani.out","w",stdout); int n,len,lt; scanf("%d",&n); while(n--) { scanf("%s",s); len=strlen(s); top=0; for(int i=0;i<len;i++) if(s[i]==\'4\' || s[i]==\'7\') continue; else if(s[i]!=\'3\') st[++top]=s[i]; else { if(st[top]==\'1\') top--; else st[++top]=\'3\'; } if(top) for(int i=1;i<=top;i++) putchar(st[i]); else putchar(\'0\'); printf("\\n"); } }
枚举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<iostream> #include<algorithm> #define N 1000001 using namespace std; int st[N][21]; int p,n; int logg2[N]; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-\'0\'; c=getchar(); } } void stpre() { p=log2(n); for(int j=1,k=2;j<=p;j++,k<<=1) for(int i=1;i+k-1<=n;i++) st[i][j]=min(st[i][j-1],st[i+(k>>1)][j-1]); for(int i=1;i<=n;i++) logg2[i]=log2(i); } int getmin(int s,int t) { p=logg2[t-s+1]; int len=1<<p; return min(st[s][p],st[t-len+1][p]); } int main() { freopen("dota.in","r",stdin); freopen("dota.out","w",stdout); int A,B,k; read(n); read(A); read(B); read(k); for(int i=1;i<=n;i++) read(st[i][0]); stpre(); int Sa,Sb,Ta,Tb,Ma,Mb,Mi; int ans=0; int l,r,mid,tmp; for(int i=A+1;i<=n-A-k+1;i++) { Ta=i-1; Sb=i+k; Tb=max(Sb+A-1,B+i-A+Sb-Ta-2); Ma=getmin(i-A,Ta); Mb=getmin(Sb,Tb); l=1; r=i-A; tmp=min(Ma,Mb); while(l<=r) { mid=l+r>>1; Tb=max(Sb+A-1,B+mid+Sb-Ta-2); Ma=getmin(mid,Ta); Mb=getmin(Sb,Tb); tmp=max(tmp,min(Ma,Mb)); if(Ma<Mb) l=mid+1; else if(Ma==Mb) break; else r=mid-1; } ans=max(ans,tmp); } printf("%d",ans); }
数位DP
dp[i][j][0/1] 前i位匹配到X的第j位,是否已经包含1个X的数的个数
二分,计算<=mid的数里的答案
其中的匹配用kmp
#include<cstdio> #include<cstring> using namespace std; typedef long long LL; LL L,R,K; LL dp[19][19][2]; int len,f[19]; char X[19]; int a[19],cnt; void kmp() { len=strlen(X); int j; for(int i=1;i<len;i++) { j=f[i]; while(j && X[i]!=X[j]) j=f[j]; f[i+1]=X[i]==X[j] ? j+1 : 0; } } LL dfs(int dep,int w,bool lim,bool get) { if(!dep) return get; if(!lim && ~dp[dep][w][get]) return dp[dep][w][get]; LL res=0; int k=lim ? a[dep] : 9; int j; for(int i=0;i<=k;i++) { j=w; while(j && X[j]-\'0\'!=i) j=f[j]; if(X[j]-\'0\'==i) j++; res+=dfs(dep-1,j,lim&&(i==k),get||(j==len)); } return lim ? res : dp[dep][w][get]=res; } LL query(LL lim) { int cnt=0; while(lim) { a[++cnt]=lim%10; lim/=10; } memset(dp,-1,sizeof(dp)); return dfs(cnt,0,true,false); } int main() { freopen("spenum.in","r",stdin); freopen("spenum.out","w",stdout); scanf("%I64d%I64d%s%I64d",&L,&R,X,&K); kmp(); LL tmp=query(L-1); if(query(R)<K) { puts("Hey,wake up!"); return 0; } LL l=L,r=R,ans,mid; while(l<=r) { mid=l+r>>1; if(query(mid)-tmp<K) l=mid+1; else ans=mid,r=mid-1; } printf("%I64d",ans); }
以上是关于2017北京国庆刷题Day6 morning的主要内容,如果未能解决你的问题,请参考以下文章