题意:
给C组数据,每组都满足的最小~第S小的数
每组数据有X,和k个R,如果N%X=任意一个R就表示满足这组数据
思路:
先用的CRT…TLE…(算了算…好爆炸的时间复杂度
如果是小数据的话,我们可以用CRT
如果是大数据就不行了,
因为数据很多,所以我们如果用枚举,随机到每个X[i]上的概率就比较高
我们可以找到最小的k[i]/X[i]来枚举t
因为可能数据弄出来不到S个,这时候我们就要手动添加大小,所以CRT里也要while,
别忘了最后的换行…
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
const int maxn = 15;
const int inf=(1<<28)-1;
int C,S;
LL Mod[maxn],k[maxn],r[maxn][105],R[15];
set<LL>Set[maxn];
vector<LL>Ans;
void Solve1(int pos)
{
for(int i=1;i<=C;++i)
if(i!=pos)
{
Set[i].clear();
for(int j=1;j<=k[i];++j)
Set[i].insert(r[i][j]);
}
int t=0;
while(S)
{
for(int i=1;i<=k[pos];++i)
{
LL Now=t*Mod[pos]+r[pos][i];
if(!Now) continue;
bool flag=true;
for(int j=1;j<=C;++j)
if(j!=pos&&!Set[j].count(Now%Mod[j]))
flag=false;
if(flag)
{
printf("%lld\n",Now);
if(--S==0) break;
}
}
++t;
}
}
void exgcd(LL a, LL b, LL &d, LL &x, LL &y)//扩展欧几里德求逆元
{
if (b == 0)
d = a, x = 1, y = 0;
else
{
exgcd(b, a%b, d, y, x);
y -= x * (a / b);
}
}
LL CRT(LL a[],LL m[],LL n)//中国剩余定理求解
{
LL aa = a[1];
LL mm = m[1];
for (int i=1; i<=n; i++)
{
LL sub = (a[i] - aa);
LL d, x, y;
exgcd(mm, m[i], d, x, y);
if (sub % d) return -1;
LL new_m = m[i]/d;
new_m = (sub/d*x%new_m+new_m)%new_m;
aa = mm*new_m+aa;
mm = mm*m[i]/d;
}
aa = (aa+mm)%mm;
return aa;
}
void dfs(int pos)
{
if(pos==C+1)
{
Ans.push_back(CRT(R,Mod,C));
return ;
}
for(int i=1;i<=k[pos];++i)
{
R[pos]=r[pos][i];
dfs(pos+1);
}
}
void Solve2()
{
Ans.clear();
dfs(1);
sort(Ans.begin(),Ans.end());
LL M=1,t=0;
for(int i=1;i<=C;++i)
M*=Mod[i];
while(S)
{
int Size=Ans.size();
for(int i=0;i<Size;++i)
{
LL Now=t*M+Ans[i];
if(Now>0)
{
printf("%lld\n",Now);
if(--S==0) break;
}
}
++t;
}
}
int main()
{
while(~scanf("%d%d",&C,&S)&&!(C==0&&S==0))
{
LL Sum=1;
int pos=1;
for(int i=1;i<=C;++i)
{
scanf("%lld%lld",&Mod[i],&k[i]);
Sum*=k[i];
for(int j=1;j<=k[i];++j)
scanf("%lld",&r[i][j]);
sort(r[i]+1,r[i]+k[i]+1);
if(k[pos]*Mod[i]>k[i]*Mod[pos])
pos=i;
}
if(Sum>10000) Solve1(pos);
else Solve2();
printf("\n");
}
return 0;
}