【BZOJ】3326: [Scoi2013]數數-數位DP

傳送門:bzoj3326


題解

這題快把我寫自閉了。。。
因爲自己設的狀態很少,一遍遍重寫轉移又把自己叉掉,(一道題做了一場比賽的時間。。。

FxF_x表示[1,x][1,x]的答案,則ans=FrFl1ans=F_r-F_{l-1}

對於FxF_x,從高位到低位處理,設fif_i表示處理到第ii位,[1,x][1,x]中以第ii位結尾且不達到數的上界(前ii位存在某位嚴格小於原數)的子串個數。gi,0/1g_{i,0/1}分別表示[1,x][1,x]中以第ii位結尾且達到/不達到數的上界的子串總貢獻(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章