uva 11754 中国剩余定理

// UVa11754 Code Feat
// Rujia Liu
typedef long long LL;

// 即使a, b在int范围内,x和y有可能超出int范围
void gcd(LL a, LL b, LL& d, LL& x, LL& y) {
  if(!b){ d = a; x = 1; y = 0; }
  else{ gcd(b, a%b, d, y, x); y -= x*(a/b); }
}

// n个方程:x=a[i](mod m[i]) (0<=i<n)
LL china(int n, int* a, int *m) {
  LL M = 1, d, y, x = 0;
  for(int i = 0; i < n; i++) M *= m[i];
  for(int i = 0; i < n; i++) {
    LL w = M / m[i];
    gcd(m[i], w, d, d, y);
    x = (x + y*w*a[i]) % M;
  }
  return (x+M)%M;
}

#include<cstdio>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;

const int maxc = 9;
const int maxk = 100;
const int LIMIT = 10000;
set<int> values[maxc];
int C, X[maxc], k[maxc];
int Y[maxc][maxk];

void solve_enum(int S, int bc) {
  for(int c = 0; c < C; c++) if(c != bc) {
    values[c].clear();
    for(int i = 0; i < k[c]; i++) values[c].insert(Y[c][i]);
  }
  for(int t = 0; S != 0; t++) {
    for(int i = 0; i < k[bc]; i++) {
      LL n = (LL)X[bc]*t + Y[bc][i];
      if(n == 0) continue; // 只输出正数解
      bool ok = true;
      for(int c = 0; c < C; c++) if(c != bc)
        if(!values[c].count(n % X[c])) { ok = false; break; }
      if(ok) { printf("%lld\n", n); if(--S == 0) break; }
    }
  }
}

int a[maxc]; // 搜索对象,用于中国剩余定理
vector<LL> sol;

void dfs(int dep) {
  if(dep == C)
    sol.push_back(china(C, a, X));
  else for(int i = 0; i < k[dep]; i++) {
    a[dep] = Y[dep][i];
    dfs(dep + 1);
  }
}

void solve_china(int S) {
  sol.clear();
  dfs(0);
  sort(sol.begin(), sol.end());

  LL M = 1;
  for(int i = 0; i < C; i++) M *= X[i];

  vector<LL> ans;
  for(int i = 0; S != 0; i++) {
    for(int j = 0; j < sol.size(); j++) {
      LL n = M*i + sol[j];
      if(n > 0) { printf("%lld\n", n); if(--S == 0) break; }
    }
  }
}

int main() {
  int S;
  while(scanf("%d%d", &C, &S) == 2 && C) {
    LL tot = 1;
    int bestc = 0;
    for(int c = 0; c < C; c++) {
      scanf("%d%d", &X[c], &k[c]);
      tot *= k[c];
      for(int i = 0; i < k[c]; i++) scanf("%d", &Y[c][i]);
      sort(Y[c], Y[c]+k[c]);
      if(k[c]*X[bestc] < k[bestc]*X[c]) bestc = c;
    }
    if(tot > LIMIT) solve_enum(S, bestc);
    else solve_china(S);
    printf("\n");
  }
  return 0;
}


书上的代码;

题目大意:求一个数N,给出C和S,表示有C个条件,每个条件有X 和 k,然后是该个条件的k个yi,即NmodX=yj,输出满足的最小的S个N,要求正整数。
解题思路:total为所有的k的乘积,也就是可以作为一组完整限定条件的可能数,当个确定条件可以用中国剩余定理处理。但是如果total太大的话,处理的情况比较多。不过total数大的时候,可以通过枚举N来判断,找到一组k/x最小的最为枚举基准,然后判断即可。

你可能感兴趣的:(uva 11754 中国剩余定理)