UVA 11754 - Code Feat

题意:给定一个c个x, y1,y2,y3..yk形式,前s小的答案满足s % x在集合y1, y2, y3 ... yk中

思路:LRJ大白例题,分两种情况讨论
1、所有x之积较小时候,暴力枚举每个集合选哪个y,然后中国剩余定理求解
2、所有x之积较大时候,选定一个k/x尽可能小的序列,枚举x * t + y (t = 1, 2, 3...)去暴力求解。

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
 
using namespace std;
 
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
 
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
 
const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));
 
const int maxc = 20;
const int maxs = 20;
const int maxk = 100 + 20;
int C, S;
int X[maxc], K[maxc];
int G[maxc][maxk];
int ans[maxs];
int sel[maxc];
vector<LL> sol;
 
void extendedGcd(LL a, LL b, LL & d, LL & x, LL & y) {
    if(!b) { d = a; x = 1; y = 0; }
    else { extendedGcd(b, a%b, d, y, x); y -= x*(a/b); }
}
 
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];
        extendedGcd(m[i], w, d, d, y);
        x = (x + y*w*a[i]) % M;
    }
    return (x+M) % M;
}
 
void dfs(int cur) {
    if(cur == C) {
        LL tans = china(C, sel, X);
        sol.push_back(tans);
        return ;
    }
    for(int i=0; i<K[cur]; i++) {
        sel[cur] = G[cur][i];
        dfs(cur+1);
    }
}
 
void solveChina() {
    sol.clear();
    dfs(0);
    sort(sol.begin(), sol.end());
    LL M = 1;
    for(int i=0; i<C; i++) M *= X[i];
    for(int i=0; S; i++) {
        for(int j=0; j<sol.size(); j++) {
            LL n = M * i + sol[j];
            if(n > 0) { P64I(n); if(--S == 0) break; }
        }
    }
}
 
set<int> values[maxc];
void solveEnum(int bc) {
    for(int i=0; i<C; i++) if(i != bc) {
        values[i].clear();
        for(int j=0; j<K[i]; j++) values[i].insert(G[i][j]);
    }
    for(int t = 0; S; t++) {
        for(int i=0; i<K[bc]; i++) {
            LL x = (LL)t * X[bc] + G[bc][i];
            if(!x) continue;
            bool ok = true;
            for(int c=0; c<C; c++) if(c != bc) {
                if(!values[c].count(x%X[c])) { ok = false; break; }
            }
            if(ok) { P64I(x); if(--S == 0) break; }
        }
    }
}
 
int main() {
 
    while(scanf("%d%d", &C, &S) != EOF && C) {
        int totK = 1;
        int tmini = 0;
        for(int i=0; i<C; i++) {
            scanf("%d%d", &X[i], &K[i]);
            totK *= K[i];
            if(K[i] * X[tmini] < X[i] * K[tmini]) tmini = i;
            for(int j=0; j<K[i]; j++) {
                scanf("%d", &G[i][j]);
            }
            sort(G[i], G[i]+K[i]);
        }
        if(totK <= 10000) solveChina();
        else solveEnum(tmini);
        putchar('\n');
    }
 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/HNUST_LIZEMING/article/details/81430496