虚高 *2800,放模拟赛 T1 人均切了。
这是 zlt 说的,不是我说的,我还是觉得没那么虚高的。
首先显然是数位 dp。
一个关键点就是怎么计算 \(f_i\times f_{i+1}\)。会发现可以将为 \(4\) 的位置看作 \(0\),否则为 \(1\),则二进制下 \(f_{i+1}=f_i+1\)。此时问题就变成了进位所带来的贡献。
考虑一个数进位的条件及发生的变化。进位时,一个最大后缀 \(7\) 连续段会变成 \(4\),然后它前面接着的一个 \(4\) 会变成 \(7\),再前面的数全部不变。于是我们可以在数位 dp 的过程中找到那个 \(4\),然后后面的 \(7\) 都是确定的,直接预处理计数。
接下来,只用考虑在 \(f_i,f_{i+1}\) 前面同时加上一个数的转移了。设 \(f_i=a,f_{i+1}=b\),前面加上 \(x=4/7\times10^k\)。则原本 \(a\times b\) 的贡献会变成 \((x+a)\times(x+b)=x^2+x\times(a+b)+a\times b\)。所以可以在数位 dp 时记录选出 \(f_i,f_{i+1}\) 的方案数,所有 \(f_i,f_{i+1}\) 的方案的 \(f_i+f_{i+1}\) 的和,所有 \(f_i,f_{i+1}\) 的方案的 \(f_i\times f_{i+1}\) 的和,上述第三种情况可以根据上面列出的式子转移,其他两种情况也是好推的。
于是再套一些数位 dp 基本操作即可。你不会数位 dp 我也讲不懂啊可能需要感性理解一下。
code:
点击查看代码
int n,m,b[13],c[13],f[N],g[N],pw[N],a[N],dp[N][3][2];
char s[N],t[N];bool pd[N];
il int Mod(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dfs(int u,int p,int lim){
if(u==n+1)return 0;
if(~dp[u][p][lim])return dp[u][p][lim];
int mx=lim?c[a[u]]:2,ret=0;
rep(i,1,mx){
int lm=lim&&i==mx;
if(i==1&&!lm){
if(p==0)ret=Mod(ret,1);
if(p==1)ret=Mod(ret,Mod(Mod(1ll*b[1]*pw[n-u]%mod,g[n-u]),Mod(1ll*b[2]*pw[n-u]%mod,f[n-u])));
if(p==2)ret=Mod(ret,(1ll*Mod(1ll*b[1]*pw[n-u]%mod,g[n-u])*Mod(1ll*b[2]*pw[n-u]%mod,f[n-u])%mod));
}
if(p==0)ret=Mod(ret,dfs(u+1,0,lm));
if(p==1)ret=Mod(ret,Mod(dfs(u+1,1,lm),2ll*b[i]*pw[n-u]%mod*dfs(u+1,0,lm)%mod));
if(p==2)ret=Mod(ret,Mod(dfs(u+1,2,lm),Mod(1ll*b[i]*pw[n-u]%mod*dfs(u+1,1,lm)%mod,1ll*b[i]*pw[n-u]%mod*b[i]%mod*pw[n-u]%mod*dfs(u+1,0,lm)%mod)));
}
return dp[u][p][lim]=ret;
}
int calc(char *s){
mems(dp,-1);
rep(i,1,n)a[i]=s[i]-'0';
pd[n+1]=1;
drep(i,n,1)pd[i]=pd[i+1]&(a[i]==b[2]);
return dfs(1,2,1);
}
void Yorushika(){
scanf("%s%s",s+1,t+1),n=strlen(s+1);
b[1]=4,b[2]=7;
f[0]=g[0]=0,pw[0]=1;
rep(i,1,n)f[i]=(10ll*f[i-1]+b[1])%mod,g[i]=(10ll*g[i-1]+b[2])%mod,pw[i]=10ll*pw[i-1]%mod;
c[b[1]]=1,c[b[2]]=2;
printf("%d\n",Mod(calc(t),mod-calc(s)));
}
signed main(){
int t=1;
// scanf("%d",&t);
while(t--)
Yorushika();
}