题意概述:
有一个正整数$N$满足$C$个条件,每个条件都形如“它除以$X$的余数在集合$\{Y_1, Y_2, ..., Y_k\}$中”,所有条件中的$X$两两互质,
你的任务是找出最小的S个解。
数据范围:
$1\leq C\leq9, 1 \leq S \leq 10, X \geq 2, 1 \leq k \leq 100, 0 \leq Y_i \leq X$
分析:
如果每个集合元素个数为1,那么我们直接使用中国剩余定理求解即可。
因此我们想到枚举余数,但是余数的组合最多会有$100^9$种可能,太多了。我们发现加入$k$的积不大的话,使用这种方法是可行的。比如
我们假设每个集合元素都不超过5。而当集合元素增加时,由于可行解是在模$M = \prod X_i$下的在枚举复杂度提高的同时也意味着可行解在
数轴上变得稠密,这意味着我们可以通过从小到大枚举答案并判定的方法解决。为了加快此过程,我们希望不可行的枚举尽快被否定,因此我们
希望首先使用$k$较小并且$X$较大的条件判定,因为这个条件是更强的,于是考虑按照$\frac{k}{X}$从小到大的顺序检验答案$i$是否满足当前
条件。由此问题便可解决。
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <iostream>
#include <assert.h>
#define pi acos(-1.)
using namespace std;
typedef long long ll;
const int int_inf = 0x3f3f3f3f;
const ll ll_inf = 0x3f3f3f3f3f3f3f3f;
const int INT_INF = (int)((1ll << ) - );
const int mod = 1e9 + ;
const double double_inf = 1e30;
typedef unsigned long long ul;
#pragma comment(linker, "/STACK:102400000,102400000")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define mp make_pair
#define st first
#define nd second
#define keyn (root->ch[1]->ch[0])
#define lson (u << 1)
#define rson (u << 1 | 1)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pb push_back
#define type(x) __typeof(x.begin())
#define foreach(i, j) for(type(j)i = j.begin(); i != j.end(); i++)
#define FOR(i, s, t) for(int i = (s); i <= (t); i++)
#define ROF(i, t, s) for(int i = (t); i >= (s); i--)
#define dbg(x) cout << x << endl
#define dbg2(x, y) cout << x << " " << y << endl
#define clr(x, i) memset(x, (i), sizeof(x))
#define maximize(x, y) x = max((x), (y))
#define minimize(x, y) x = min((x), (y))
#define low_bit(x) ((x) & (-x)) inline int readint(){
int x;
scanf("%d", &x);
return x;
} inline int readstr(char *s){
scanf("%s", s);
return strlen(s);
} class cmpt{
public:
bool operator () (const int &x, const int &y) const{
return x > y;
}
}; int Rand(int x, int o){
//if o set, return [1, x], else return [0, x - 1]
if(!x) return ;
int tem = (int)((double)rand() / RAND_MAX * x) % x;
return o ? tem + : tem;
} void data_gen(){
srand(time());
freopen("in.txt", "w", stdout);
int times = ;
printf("%d\n", times);
while(times--){
int r = Rand(, ), a = Rand(, ), c = Rand(, );
int b = Rand(r, ), d = Rand(r, );
int m = Rand(, ), n = Rand(m, );
printf("%d %d %d %d %d %d %d\n", n, m, a, b, c, d, r);
}
} struct cmpx{
bool operator () (int x, int y) { return x > y; }
};
int debug = ;
int dx[] = {-, , , };
int dy[] = {, , -, };
//-------------------------------------------------------------------------
int C, S;
ll mt[][];
ll X[], k[];
ll ans[];
ll buf[];
ll w[], _w[];
ll M;
int id[];
pair<pll, int> _buf[];
const int lim = 1e5; void egcd(ll a, ll b, ll &d, ll &x, ll &y){
if(!b){
d = a, x = , y = ;
return;
}
egcd(b, a % b, d, x, y);
ll x1 = x, y1 = y;
x = y1, y = x1 - a / b * y1;
} void dfs(int pos){
if(pos == C + ){
ll tem = ;
FOR(i, , C) tem += buf[i] * w[i] % M * _w[i] % M, tem %= M;
if(!tem) tem = M;
FOR(i, , S - ) ans[i + S] = tem + M * i;
sort(ans, ans + * S);
return;
}
FOR(i, , k[pos]){
buf[pos] = mt[pos][i];
dfs( + pos);
}
} bool cmp(pair<pll, int> x, pair<pll, int> y){
return x.st.st * y.st.nd < x.st.nd * y.st.st;
} void enu_solve(){
FOR(i, , C) _buf[i] = mp(mp(k[i], X[i]), i);
sort(_buf + , _buf + C + );
FOR(i, , C) id[i] = _buf[i].nd;
int cnt = ;
int bg = ;
while(cnt < S){
int ok1 = ;
FOR(i, , C){
int j = id[i];
int tem = bg % X[j];
int sz = k[j];
int ok = ;
FOR(u, , sz) if(tem == mt[j][u]) { ok = ; break; }
if(!ok) { ok1 = ; break; }
}
if(ok1) ans[cnt++] = bg;
bg++;
}
} void crt_solve(){
M = ;
FOR(i, , C) M *= X[i];
FOR(i, , C) w[i] = M / X[i] % M;
FOR(i, , C){
ll d, x, y;
egcd(w[i], X[i], d, x, y);
_w[i] = (x % X[i] + X[i]) % X[i];
}
clr(ans, ll_inf);
dfs();
} void solve(){
ll num = ;
int ok = ;
FOR(i, , C){
num *= k[i];
if(num > lim){
ok = ;
break;
}
}
if(ok) crt_solve();
else enu_solve();
} //-------------------------------------------------------------------------
int main(){
//data_gen(); return 0;
//C(); return 0;
debug = ;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(debug) freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
while(~scanf("%d%d", &C, &S) && C){
FOR(i, , C){
X[i] = readint(), k[i] = readint();
FOR(j, , k[i]) mt[i][j] = readint();
}
solve();
FOR(i, , S - ) printf("%lld\n", ans[i]);
printf("\n");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
return ;
}
code: