这道题的题面意思就是
给出C,S,C代表着条件个个数,S代表你要输出答案的个数(因为肯定有多个答案);
然后下面有C行,每行有先是X,k;然后后面紧跟着k个数字。满足这个条件的情况就是N%X=k1,k2...ki;
要你求出最小的N满足这C个条件;
看题面,就知道肯定有关中国剩余定理。
有两种方法:
第一,强行暴利枚举,也就是从全部条件的k中,找出所有的组合,用扩展中国剩余定理就能得到答案;
第二,枚举N,就是选择一个条件,用这个条件中的k1,k2...kn,去枚举N,然后判断满不满足剩下的C-1个条件。
问题在于,怎么选取这个条件呢?我们的目的是降低时间复杂度,所以选取k/x最小的就可以了,至于为什么,打打草稿就能得出结论
下面附上代码
#include
using namespace std;
#define ll long long int
#define fin(a,n) for(int i=a;i<=n;i++)
#define fjn(a,n) for(int j=a;j<=n;j++)
#define fni(n,a) for(int i=n;i>=1;i--)
#define fnj(n,a) for(int j=n;j>=1;j--)
const int maxn=1e2+10;
const int inf=1e5+10;
ll C,S;
int Y[maxn][maxn],X[maxn],k[maxn];
vectorans;
int a[maxn];
setval[maxn];
void exgcd(ll a, ll b, ll& d, ll& x, ll& y)//扩展欧几里得求
{
if(!b)
{
d = a;
x = 1;
y = 0;
}
else
{
exgcd(b, a%b, d, y, x);
y -= x*(a/b);
}
}
ll china(int n,int *a,int *m)//扩展中国剩余定理
{
ll res=0,d,y,M;
M=1;
fin(1,n)
M*=m[i];
fin(1,n)
{ ll w=M/m[i];
exgcd(m[i],w,d,d,y);
res=(res+a[i]*w*y)%M;
}
return (res%M+M)%M;
}
void dfs(int dep)//dfs求组合数
{
if(dep==C+1)
ans.push_back(china(C,a,X));
for(int i=1;i<=k[dep];i++)
{
a[dep]=Y[dep][i];
dfs(dep+1);
}
}
void solve(int S)//正常方法,dfs枚举答案
{ ans.clear();//清空答案组
dfs(1);//从第一组开始枚举
sort(ans.begin(),ans.end());
ll M=1;
fin(1,C)
{
M*=X[i];
}
for(int i=0;S!=0;i++)
{
for(int j=0;j0)//这里判断很必要,因为有可能这个数是0
{
printf("%lld\n",ans[j]+M*i);
S--;
if(S==0)break;
}
}
}
}
void solve_max(int S,int in)
{
fin(1,C)
{ val[i].clear();//清空当前组
if(i!=in)//如果不是出发组
{ for(int j=1;j<=k[i];j++)
val[i].insert(Y[i][j]);//输入当前数据
}
}
for(int t=0;S!=0;t++)
{
for(int i=1;i<=k[in];i++)
{
ll ans=X[in]*t+Y[in][i];//枚举答案
if(ans==0)
continue;
bool ok=true;//先判断这个数符合
for(int j=1;j<=C;j++)//从第一组开始判断
{
if(j!=in)//不是入口组
{
if(!val[j].count(ans%X[j]))//如果当前组不符合
{
ok=false;//修改bool
break;
}
}
}
if(ok)
{
printf("%lld\n",ans);
S--;
if(S==0)break;
}
}
}
}
int main()
{
while(scanf("%d %d",&C,&S)==2&&C)
{ int in=1;//in表示入口
ll tot=1;
//if(C==0&&S==0)return 0;
fin(1,C)
{
scanf("%d %d",&X[i],&k[i]);
tot*=k[i];
fjn(1,k[i])
{
scanf("%d",&Y[i][j]);
}
sort(Y[i]+1,Y[i]+1+k[i]);
if(k[in]*X[i]>k[i]*X[in])
in=i;
}
if(tot>inf)
solve_max(S,in);
else
solve(S);
printf("\n");
}
}