[hdu5389 Zero Escape]数根的性质,DP
题意:把n个数(1-9)放到A集合和B集合里面去,使得A集合里面的数的数根为a,B集合里面的数的数根为b,也可以只放在A或B任一个集合里面。求方法总数。比如A={2,4,5},则A的数根为[2+4+5]=[11]=[2]=2
思路:一个数为a,则它的数根b=(a-1)%9+1=(digit-1)%9+1,digit是a的十进制各位上的数的和。如果存在解,那么任选一些数放到A集合里面,使得A集合的数根为a,那么B集合的数根一定为b。由公式可知,数根可以转化为余数来做,令dp[i][x]表示考虑前i个数,使得A里面数的和对9的余数为x的方法总数,则有dp[i][x]=dp[i-1][x]+dp[i-1][(x-a[i]+9)%9]。最后需要考虑只放一个集合的情况。
#include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define copy(a, b) memcpy(a, b, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; //#ifndef ONLINE_JUDGE void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} //#endif template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} template<typename T> void V2A(T a[],const vector<T>&b){for(int i=0;i<b.size();i++)a[i]=b[i];} template<typename T> void A2V(vector<T>&a,const T b[]){for(int i=0;i<a.size();i++)a[i]=b[i];} const double PI = acos(-1.0); const int INF = 1e9 + 7; const double EPS = 1e-8; /* -------------------------------------------------------------------------------- */ template<int mod> struct ModInt { const static int MD = mod; int x; ModInt(ll x = 0): x(x % MD) {} int get() { return x; } ModInt operator + (const ModInt &that) const { int x0 = x + that.x; return ModInt(x0 < MD? x0 : x0 - MD); } ModInt operator - (const ModInt &that) const { int x0 = x - that.x; return ModInt(x0 < MD? x0 + MD : x0); } ModInt operator * (const ModInt &that) const { return ModInt((long long)x * that.x % MD); } ModInt operator / (const ModInt &that) const { return *this * that.inverse(); } ModInt operator += (const ModInt &that) { x += that.x; if (x >= MD) x -= MD; } ModInt operator -= (const ModInt &that) { x -= that.x; if (x < 0) x += MD; } ModInt operator *= (const ModInt &that) { x = (long long)x * that.x % MD; } ModInt operator /= (const ModInt &that) { *this = *this / that; } ModInt inverse() const { int a = x, b = MD, u = 1, v = 0; while(b) { int t = a / b; a -= t * b; std::swap(a, b); u -= t * v; std::swap(u, v); } if(u < 0) u += MD; return u; } }; typedef ModInt<258280327> mint; const int maxn = 1e5 + 7; mint dp[maxn][10]; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int T, n, a, b, x; cin >> T; while (T --) { cin >> n >> a >> b; dp[0][0] = 1; a = a % 9; b = b % 9; int tot = 0; for (int i = 1; i <= n; i ++) { scanf("%d", &x); for (int j = 0; j < 9; j ++) { dp[i][j] = dp[i - 1][j] + dp[i - 1][(j - x + 9) % 9]; } tot = (tot * 10 + x) % 9; } mint ans = 0; if (tot == a && b > 0) ans += 1; if (tot == b && a > 0) ans += 1; if(tot == (a + b) % 9) ans += dp[n][a].get(); printf("%d\n", ans.get()); } return 0; }