UVa 11754 (中国剩余定理 枚举) Code Feat

如果直接枚举的话,枚举量为k1 * k2 *...* kc

根据枚举量的不同,有两种解法。

  • 枚举量不是太大的话,比如不超过1e4,可以枚举每个集合中的余数Yi,然后用中国剩余定理求解。解的个数不够S个的时候,要把这些解分别加上M、2M...(M = X1 * X2 *...* Xc)
  • 如果上述枚举量太大的话,直接枚举x。找一个k/X最小的条件,然后让x = t * X + Yi开始枚举,因为这样枚举x增长得最快,所以枚举次数也就最少。如果符合要求的话则输出。

上面两种方法都要注意所找到的解为正整数。

  1 typedef long long LL;
  2 
  3 void gcd(LL a, LL b, LL& d, LL& x, LL& y)
  4 {
  5     if(!b) { d = a; x = 1; y = 0; }
  6     else { gcd(b, a%b, d, y, x); y -= x*(a/b); }
  7 }
  8 
  9 LL china(int n, int* a, int* m)
 10 {
 11     LL M = 1, d, y, x = 0;
 12     for(int i = 0; i < n; i++) M *= m[i];
 13     for(int i = 0; i < n; i++)
 14     {
 15         LL w = M / m[i];
 16         gcd(m[i], w, d, d, y);
 17         x = (x + y*w*a[i]) % M;
 18     }
 19     return (x+M)%M;
 20 }
 21 
 22 #include <cstdio>
 23 #include <vector>
 24 #include <set>
 25 #include <algorithm>
 26 #include <cstring>
 27 using namespace std;
 28 
 29 const int maxc = 9;
 30 const int maxk = 100;
 31 const int LIMIT = 10000;
 32 int C, S;
 33 int bestc;
 34 int X[maxc], Y[maxc][maxk], k[maxc];
 35 set<int> values[maxc];
 36 
 37 void solve_enum()
 38 {
 39     for(int c = 0; c < C; c++) if(c != bestc)
 40     {
 41         values[c].clear();
 42         for(int i = 0; i < k[c]; i++)
 43             values[c].insert(Y[c][i]);
 44     }
 45 
 46     for(int t = 0; S != 0; t++)
 47     {
 48         for(int i = 0; i < k[bestc]; i++)
 49         {
 50             LL n = (LL)t * X[bestc] + Y[bestc][i];//枚举解
 51             if(n == 0) continue;
 52             bool ok = true;
 53             for(int c = 0; c < C; c++) if(c != bestc)//判断是否符合要求
 54                 if(!values[c].count(n % X[c])) { ok = false; break; }
 55             if(ok) { printf("%lld\n", n); if(--S == 0) { break; } }
 56         }
 57     }
 58 }
 59 
 60 int a[maxc];
 61 vector<LL> sol;
 62 
 63 void dfs(int d)
 64 {
 65     if(d == C) sol.push_back(china(C, a, X));
 66     else for(int i = 0; i < k[d]; i++)
 67     {
 68         a[d] = Y[d][i];
 69         dfs(d + 1);
 70     }
 71 }
 72 
 73 void solve_china()
 74 {
 75     sol.clear();
 76     dfs(0);
 77     sort(sol.begin(), sol.end());
 78 
 79     LL M = 1;
 80     for(int i = 0; i < C; i++) M *= X[i];
 81 
 82     for(int i = 0; S != 0; i++)
 83     {
 84         for(int j = 0; j < sol.size(); j++)
 85         {
 86             LL n = M * i + sol[j];
 87             if(n == 0) continue;
 88             printf("%lld\n", n);
 89             if(--S == 0) break;
 90         }
 91     }
 92 }
 93 
 94 int main()
 95 {
 96     freopen("in.txt", "r", stdin);
 97 
 98     while(scanf("%d%d", &C, &S) == 2 && C && S)
 99     {
100         bestc = 0;
101         int tot = 1;
102         for(int c = 0; c < C; c++)
103         {
104             scanf("%d%d", &X[c], &k[c]);
105             tot *= k[c];
106             if(k[c] * X[bestc] < k[bestc] * X[c]) bestc = c;
107             for(int i = 0; i < k[c]; i++)
108                 scanf("%d", &Y[c][i]);
109             sort(Y[c], Y[c] + k[c]);
110         }
111 
112         if(tot > LIMIT) solve_enum();
113         else solve_china();
114         printf("\n");
115     }
116 
117     return 0;
118 }
代码君

 

posted @ 2015-03-08 20:09  AOQNRMGYXLMV  阅读(413)  评论(0编辑  收藏  举报