标签:while 表示 mem 判断 string eve splay click log
12345 5
我们运用状压DP,令 f[j][opt] 表示当前余数为 j,状态为opt的方案。
状态记录的是:各个数字被用了几次。
那么我们就可以状压了。先DFS出每个状态,记sum[k]表示后缀积,那么显然 从 opt 转移到 第k个数字多用一次的状态 就是 opt + sum[k + 1]。
注意判断一下首位不能为0。
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 #include<vector> 9 #include<queue> 10 using namespace std; 11 typedef long long s64; 12 13 const int ONE = 500005; 14 const int MOD = 998244353; 15 16 int n, m; 17 int num; 18 int vis[ONE], Num[20], sum[20]; 19 int f[105][200005]; 20 int Sta[ONE][10]; 21 char ch[ONE]; 22 23 int get() 24 { 25 int res=1,Q=1;char c; 26 while( (c=getchar())<48 || c>57 ) 27 if(c==‘-‘)Q=-1; 28 res=c-48; 29 while( (c=getchar())>=48 && c<=57 ) 30 res=res*10+c-48; 31 return res*Q; 32 } 33 34 void Dfs(int T) 35 { 36 if(T > 10) 37 { 38 num++; 39 for(int i = 0; i <= 9; i++) 40 Sta[num][i] = vis[i]; 41 return; 42 } 43 44 for(int i = 0; i <= Num[T]; i++) 45 vis[T] = i, Dfs(T + 1); 46 } 47 48 int main() 49 { 50 scanf("%s", ch + 1); m = get(); 51 n = strlen(ch + 1); 52 53 for(int i = 1; i <= n; i++) Num[ch[i] - ‘0‘]++; 54 sum[10] = 1; for(int i = 9; i >= 0; i--) sum[i] = sum[i + 1] * (Num[i] + 1); 55 56 Dfs(0); 57 58 f[0][1] = 1; 59 for(int opt = 1; opt <= num; opt++) 60 for(int j = 0; j < m; j++) 61 if(f[j][opt]) 62 for(int k = 0; k <= 9; k++) 63 { 64 if(opt == 1 && k == 0) continue; 65 if(Sta[opt][k] >= Num[k]) continue; 66 int to = opt + sum[k + 1]; 67 f[(j * 10 + k) % m][to] += f[j][opt]; 68 f[(j * 10 + k) % m][to] %= MOD; 69 } 70 71 printf("%d", f[0][num]); 72 }
标签:while 表示 mem 判断 string eve splay click log
原文地址:http://www.cnblogs.com/BearChild/p/7532820.html