UVA - 11361 Investigating Div-Sum Property 【數位dp】
阿新 • • 發佈:2018-11-19
題目描述:有t組測試資料(T < 100),每組測試資料輸入三個整數a,b,k,1 ≤ A ≤ B < 2 31 and 0 < K < 10000.求a~b中能夠整除k並且數位和也能夠整除k的數的個數。
解題思路:設f(x)表示不超過x的非負數中滿足條件的數的個數,則本題的答案等於f(b)-f(a-1)。可以考慮用加法原理、分段求和。
設dp[d][m1][m2]表示共d個數字,其中各數字之和除以k的餘數為m1,這些數字組成的整數除以k的餘數為m2,則每個模板對應的解的個數都等於某個dp[d][m1][m2]。
遞推公式為:f(d,m1,m2)=∑f(d−1,(m1+i)%k,m2+i∗10d−1%k|0⩽i⩽9)
AC程式碼:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <queue> #include <stack> #include <vector> #include <map> #include <set> using namespace std; #define io ios::sync_with_stdio(0),cin.tie(0) #define ms(arr) memset(arr,0,sizeof(arr)) #define inf 0x3f3f3f typedef long long ll; const int mod=1e9+7; const int maxn=1e5+7; ll t,a,b,k; int dp[15][120][120];//dp[d][m1][m2]表示共d個數字,其中各數字之和除以k的餘數為m1,這些數字組成數位整數除以k的餘數為m2的整數的個數 int c[15]; ll dfs(int d,int m1,int m2,bool limit) { if(d==0) { if(m1==0&&m2==0) return 1; else return 0; } if(!limit&&dp[d][m1][m2]>=0) return dp[d][m1][m2]; int up;//up存的是當前數位的上界 if(limit)//limit表示前一數位是否達到上界 up=c[d]; else up=9; ll ans=0; for(int i=0;i<=up;i++) { ans+=dfs(d-1,(m1+i)%k,(m2*10+i)%k,limit&&(i==up)); } dp[d][m1][m2]=ans; return dp[d][m1][m2]; } ll f(int x) { int cnt=0; while(x) { c[++cnt]=x%10; x=x/10; } memset(dp,-1,sizeof(dp)); return dfs(cnt,0,0,1); } int main() { cin>>t; while(t--) { cin>>a>>b>>k; ll ans; if(k>=83) ans=0; else ans=f(b)-f(a-1); cout<<ans<<endl; } return 0; }