bzoj4980: 第一题
Posted ccz181078
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4980: 第一题相关的知识,希望对你有一定的参考价值。
Description
神犇xzyo听说sl很弱,于是出了一题来虐一虐sl。一个长度为2n(可能有前缀0)的非负整数x是good的,当且仅当
存在两个长度为n(可能有前缀0)的非负整数a、b满足a+b==10n,并且对于0~9每个数位d,都有Sd(x)==Sd(a)+Sd(
b)(Sd(x)为x的十进制中d出现了多少次)。例如0829是good的,98+02==100。给出一个长度为2n的序列,其中有些
位置是问号。将每个问号替换为0~9任意一个数位后,有多少个good数,答案对1000000007取膜。为了sl不被虐死
,快告诉他怎么写吧。
两个数相加为10^n,意味着可以将数位一部分按09,18,27,36,45配对表示较高位的情况,低位有一对19,28,37,46,55产生了一次进位,更低位可以全0。枚举哪一对数产生进位,可以算出0的出现次数-9的出现次数,1-8,2-7,3-6,4-5的值,然后做一次背包。需要特判一些情况:因为两个0可以配对,0-9的值表示的是0至少比9多几个,实际可以再把一些9换成0,但如果19产生进位,必须留下至少一个9(可能来自已确定的数位,也可能必须由?提供)而不能全部换成0。
#include<bits/stdc++.h> typedef long long i64; const int P=1e9+7; char s[100007]; int n,t[11],m=0,ts[11]; i64 f[1007],g[1007],fac[1007],fiv[1007],ans=0; i64 _ks[2077][1007],(*ks)[1007]=_ks+1027; bool d9=0; void cal(int tp){ memset(f,0,sizeof(f)); f[0]=1; for(int i=0;i<5;++i){ memset(g,0,sizeof(g)); if(ts[i]>m||i&&ts[i]<-m)return; if(!i){ while(ts[i]<-m)ts[i]+=2; for(int s=0,d=0;s<=m;++s){ i64 iv=ks[ts[i]][s]; if(!iv)continue; if(tp==1&&!d9&&(s+ts[i])%2==0)iv=(iv-fiv[s]+P)%P; for(int j=s;j<=m;++j)g[j]+=f[j-s]*iv; if(++d>6){ d=0; for(int j=0;j<=m;++j)g[j]%=P; } } }else for(int a=ts[i],b=0,d=0;a+b<=m;++a,++b)if(a>=0){ int s=a+b; i64 iv=fiv[a]*fiv[b]%P; for(int j=s;j<=m;++j)g[j]+=f[j-s]*iv; if(++d>6){ d=0; for(int j=0;j<=m;++j)g[j]%=P; } } for(int j=0;j<=m;++j)f[j]=g[j]%P; } ans=(ans+f[m]*fac[m])%P; } i64 pw(i64 a,int n){ i64 v=1; for(;n;n>>=1,a=a*a%P)if(n&1)v=v*a%P; return v; } int main(){ for(int i=fac[0]=1;i<=1000;++i)fac[i]=i*fac[i-1]%P; fiv[1000]=pw(fac[1000],P-2); for(int i=1000;i;--i)fiv[i-1]=i*fiv[i]%P; scanf("%s",s); n=strlen(s); if(n&1)return puts("0"),0; for(int i=0;i<n;++i){ if(s[i]==‘?‘)++m; else ++t[s[i]-‘0‘]; d9|=s[i]==‘9‘; } for(int i=m;i>=-m;--i){ for(int a=i,b=0;a+b<=m;++a,++b)if(a>=0)ks[i][a+b]=fiv[a]*fiv[b]%P; for(int j=0;j<=m;++j)ks[i][j]=(ks[i][j]+ks[i+2][j])%P; } for(int i=1;i<=5;++i){ for(int j=0;j<10;++j)ts[j]=t[j]; --ts[i],--ts[10-i]; for(int j=0;j<5;++j)ts[j]=ts[9-j]-ts[j]; i64 a0=ans; cal(i); a0=ans-a0; } printf("%lld\n",ans); return 0; }
以上是关于bzoj4980: 第一题的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1010 [HNOI2008] 玩具装箱toy (斜率优化第一题)
考后反思(bzoj3940 bzoj4899 bzoj3307)