https://www.hackerrank.com/contests/w28/challenges/lucky-number-eight
设dp[i][v]表示前i位数中,得到余数是v的子序列的数目。
那么产生新的状态就是,对于每一个上一次的余数v。新的余数数目就有,(v * 10 + str[i]) % 8
然后输出dp[n][0]即可。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> const int maxn = 2e5 + 20; int dp[8]; int sec[8]; char str[maxn]; const int MOD = 1e9 + 7; void work() { int n; scanf("%d", &n); scanf("%s", str + 1); for (int i = 1; i <= n; ++i) { for (int j = 0; j <= 7; ++j) sec[j] = dp[j]; for (int j = 0; j <= 7; ++j) { sec[(j * 10 + str[i] - '0') % 8] += dp[j]; if (sec[(j * 10 + str[i] - '0') % 8] >= MOD) sec[(j * 10 + str[i] - '0') % 8] -= MOD; } sec[(str[i] - '0') % 8]++; for (int j = 0; j <= 7; ++j) dp[j] = sec[j]; } int ans = dp[0]; // for (int i = 1; i <= 3; ++i) { // ans += min(dp[i], dp[8 - i]); // if (ans >= MOD) ans -= MOD; // } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }