虚高 *2800,放模拟赛 T1 人均切了。
这是 zlt 说的,不是我说的,我还是觉得没那么虚高的。
首先显然是数位 dp。
一个关键点就是怎么计算 。会发现可以将为 的位置看作 ,否则为 ,则二进制下 。此时问题就变成了进位所带来的贡献。
考虑一个数进位的条件及发生的变化。进位时,一个最大后缀 连续段会变成 ,然后它前面接着的一个 会变成 ,再前面的数全部不变。于是我们可以在数位 dp 的过程中找到那个 ,然后后面的 都是确定的,直接预处理计数。
接下来,只用考虑在 前面同时加上一个数的转移了。设 ,前面加上 。则原本 的贡献会变成 。所以可以在数位 dp 时记录选出 的方案数,所有 的方案的 的和,所有 的方案的 的和,上述第三种情况可以根据上面列出的式子转移,其他两种情况也是好推的。
于是再套一些数位 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();
}