傳送門:bzoj3326
題解
這題快把我寫自閉了。。。
因爲自己設的狀態很少,一遍遍重寫轉移又把自己叉掉,(一道題做了一場比賽的時間。。。
設表示的答案,則
對於,從高位到低位處理,設表示處理到第位,中以第位結尾且不達到數的上界(前位存在某位嚴格小於原數)的子串個數。分別表示中以第位結尾且達到/不達到數的上界的子串總貢獻(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;
}