Codeforces Gym100623J:Just Too Lucky(数位DP)
http://codeforces.com/gym/100623/attachments
题意:问1到n里面有多少个数满足:本身被其各个数位加起来的和整除。例如120 % 3 == 0,111 % 3 == 0,都算。
思路:老是写不出数位DP。。。
因为n最大为12位,所以取模的数最大可以是9*12 == 108,因此枚举这个模。
dfs记录的状态有:pos, sum, mod, remain, flag。
pos代表枚举到第几位,
sum代表数位之和,
mod代表当前枚举的模,
remain代表当前枚举的数,(做不出来主要昨天这里没考虑好,12 % 3和120 % 3是一样的结果)
flag代表前面是否达到上限。
然后最后判定的时候只要remain == 0 && mod == sum就是可行的状态。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 #define N 15 5 #define M 110 6 int dp[N][M][M][M], bit[N]; 7 8 LL dfs(int pos, int sum, int mod, int remain, int flag) { 9 if(!pos) return sum == mod && remain == 0; 10 if(~dp[pos][sum][remain][mod] && flag) return dp[pos][sum][remain][mod]; 11 int d = flag ? 9 : bit[pos]; 12 LL ans = 0; 13 for(int i = 0; i <= d; i++) 14 ans += dfs(pos - 1, sum + i, mod, (remain * 10 + i) % mod, flag || i != d); 15 if(flag) dp[pos][sum][remain][mod] = ans; 16 return ans; 17 } 18 19 LL solve(LL n) { 20 int len = 0; 21 while(n) { bit[++len] = n % 10; n /= 10; } 22 LL ans = 0; 23 for(int i = 1; i <= 108; i++) 24 ans += dfs(len, 0, i, 0, 0); 25 return ans; 26 } 27 28 int main() { 29 freopen("just.in", "r", stdin); 30 freopen("just.out", "w", stdout); 31 memset(dp, -1, sizeof(dp)); 32 LL n; cin >> n; 33 cout << solve(n) << endl; 34 return 0; 35 }