传送门:bzoj3326
题解
这题快把我写自闭了。。。
因为自己设的状态很少,一遍遍重写转移又把自己叉掉,(一道题做了一场比赛的时间。。。
设 F x F_x Fx表示 [ 1 , x ] [1,x] [1,x]的答案,则 a n s = F r − F l − 1 ans=F_r-F_{l-1} ans=Fr−Fl−1
对于 F x F_x Fx,从高位到低位处理,设 f i f_i fi表示处理到第 i i i位, [ 1 , x ] [1,x] [1,x]中以第 i i i位结尾且不达到数的上界(前 i i i位存在某位严格小于原数)的子串个数。 g i , 0 / 1 g_{i,0/1} gi,0/1分别表示 [ 1 , x ] [1,x] [1,x]中以第 i i i位结尾且达到/不达到数的上界的子串总贡献(0表示达到,1表示不达到)
具体转移详见代码,有兴趣的可以评论里问我。
总之我已经严重自闭了。
数位DP一定要想清楚再写。。。
代码
#include<bits/stdc++.h>
#define mem(f) memset(f,0,sizeof(f))
using namespace std;
typedef long long ll;
const int N=1e5+100,mod=20130427;
int n,m,B,ans,suf[N],pw[N];
int a[N],b[N],f[N],g[N][2];
inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void dc(int &x,int y){x-=y;if(x<0) x+=mod;}
inline int inc(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dec(int x,int y){x-=y;return x<0?x+mod:x;}
inline int S(int x){return ((ll)x*(x+1)>>1)%mod;}
inline int calc(int x,int n)
{return inc(dec(suf[n],(ll)suf[x]*pw[n-x]%mod),1);}
int cal(int *a,int n)
{
mem(f);mem(g);suf[0]=0;int i,j,re=0,lim;
for(i=1;i<=n;++i) suf[i]=inc((ll)suf[i-1]*B%mod,a[i]);
for(i=1;i<=n;++i){
lim=a[i];
if(i>1) f[i]=inc((ll)f[i-1]*B%mod,(ll)(i-1)*lim%mod);//previous
if(i>1) ad(f[i],(ll)dec(suf[i-1],1)*B%mod),ad(f[i],B-1);//new
if(lim>0) ad(f[i],lim-(i==1));
if(i>1) g[i][0]=inc((ll)g[i-1][0]*B%mod,(ll)(i-1)*lim%mod);//previous
ad(g[i][0],lim);//new
if(i>1){
g[i][1]=inc((ll)g[i-1][1]*B%mod*(ll)B%mod,(ll)f[i-1]*S(B-1)%mod);
ad(g[i][1],inc((ll)g[i-1][0]*B%mod*(ll)lim%mod,(ll)(i-1)*S(lim-1)%mod));
}//previous
if(i>1) ad(g[i][1],(ll)dec(suf[i-1],1)*S(B-1)%mod),ad(g[i][1],S(B-1));
if(lim>0) ad(g[i][1],S(lim-1));//new
ad(re,inc((ll)g[i][0]*calc(i,n)%mod,(ll)g[i][1]*pw[n-i]%mod));
}
return re;
}
int main(){
int i,j,k;
scanf("%d",&B);
scanf("%d",&n);for(i=1;i<=n;++i) scanf("%d",&a[i]);
scanf("%d",&m);for(i=1;i<=m;++i) scanf("%d",&b[i]);
pw[0]=1;for(i=1;i<N;++i) pw[i]=(ll)pw[i-1]*B%mod;
if(n>1 || (n==1 && a[1]!=0)){
reverse(a+1,a+n+1);
for(i=1;(!a[i]);++i);
a[i]--;for(--i;i>0;--i) a[i]=B-1;// not 9
for(;(!a[n])&& n>1;--n);
reverse(a+1,a+n+1);
}
printf("%d",dec(cal(b,m),cal(a,n)));
return 0;
}