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 }
原文地址:https://www.cnblogs.com/fightfordream/p/6650047.html