BZOJ1799 [Ahoi2009]self 同类分布[数位DP]
求出[a,b]中各位数字之和能整除原数的数的个数。
有困难的一道题。被迫看了题解:枚举每一个各位数字的和($<=162$),设计状态$f[len][sum][rest]$表示dp后面$len$位,要求这剩下的和是$sum$,并且其对$sum$取模是$rest$的方案数。
感觉也讲不出什么道理来,真的是。。经验问题啊。。。当时数位dp不太会,现在看来稍微好些了。或者也可以从最高位往后看,设前面填好的高位组成的各位和是sum,mod枚举剩rest,到最低位再检验正确性。
转移(向下一层dp)时就是把当前填的这一位数字从sum减掉,并且rest取$rest-i*10^{len-1}%p$,比如我一开始要求rest是0,第一位填3,后面的数要求的rest就变了。为什么是前面那个式子,这个可以推一下,很好推,就是剩余系相关的数学内容。然后每种sum都讨论一下,另外记搜可以带点剪枝什么的,卡卡就过啦。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define dbg(x) cerr<<#x<<" = "<<x<<endl 7 #define ddbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl 8 using namespace std; 9 typedef long long ll; 10 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 11 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 12 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 13 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 14 template<typename T>inline T read(T&x){ 15 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 16 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 17 } 18 const ll bin[20]={0,1,10,1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13,1e14,1e15,1e16,1e17,1e18}; 19 ll l,r,f[19][164][164],p; 20 int flag,b[20]; 21 inline int mod(ll x){return x<0?x+p:x;} 22 ll dp(int len,int s,int rest,bool limit){ 23 if(!len){if(!s&&!rest)return 1;else return 0;} 24 if(s<0||9*len<s)return 0;//剪枝 25 if(!limit&&~f[len][s][rest])return f[len][s][rest]; 26 int num=limit?b[len]:9;ll ret=0; 27 for(register int i=0;i<=num;++i)ret+=dp(len-1,s-i,mod(rest-i*1ll*bin[len]%p),limit&&(i==num)); 28 return limit?ret:f[len][s][rest]=ret; 29 } 30 inline ll solve(ll x){ 31 ll k=0,ret=0;while(x)b[++k]=x%10,x/=10; 32 for(p=1;p<=k*9;++p)memset(f,-1,sizeof f),ret+=dp(k,p,0,1); 33 return ret; 34 } 35 36 int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout); 37 read(l),read(r);if(l>=1e18)return printf("1\n"),0;if(r>=1e18)--r,++flag; 38 return printf("%lld\n",solve(r)-solve(l-1)+flag),0; 39 }