Code Feat UVA - 11754

原题链接

基本是抄lnj老师的代码,这种方法本蒟蒻就是被打死都想不出来= =

错误思路:

        枚举每一种组合,代入模板求解,将解排序输出

这种思路主要错在两个地方:

  1. k<=100,C<=9.最多有1009种枚举方式.TLE
  2. 枚举的组合数<要求输出的解数.此时我们需要对解+res直到解足够.但解必须是有序的,也就是说需要for循环一遍解.因为最小正整数解<res.所以不用担心某个解+res<另一个方程的解

lnj的思路:

       当组合的种类数较大时,我们需要换一种枚举方式.即直接利用余数和除数枚举被除数.再将枚举的数代入每个方程检验.

       这种方法只有在方案数较多时适用,当方案数多时检验成功率高,比暴力枚举耗时小.

       所以需要选出一个最适合的除数来作为枚举的对象.X小是不适合的,因为当另一个X大时,小的凑出来的解甚至比大的余数还小.这样就耗费了时间,因此选X大的

       余数越少,枚举量越少,因此选k小的.

当方案数少就直接dfs枚举

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <set>
  5 #include <vector>
  6 using namespace std;
  7 typedef long long ll;
  8 const int N = 110,M = 1e4;
  9 int C,T,k[15],best;//方程,解的数,余数数 
 10 ll Y[15][N],X[N>>1],res,tot,m[N/10];//余数  除数
 11 set<ll> s[N]; 
 12 vector<ll> ans;
 13 void Update()
 14 {
 15     res = 1,tot = 1; best = 1; ans.clear();
 16 }
 17 void inits()
 18 {
 19     for(int i=1;i<=C;i++)
 20     {
 21         scanf("%lld%d",&X[i],&k[i]);
 22         res*=X[i]; tot*=k[i];
 23         s[i].clear();
 24         for(int j=1;j<=k[i];j++)
 25         {
 26             scanf("%lld",&Y[i][j]);
 27             s[i].insert(Y[i][j]);
 28         }
 29         sort(Y[i]+1,Y[i]+k[i]+1);
 30         if(X[best]*k[i]<X[i]*k[best]) best = i;
 31     }
 32 }
 33 ll exgcd(ll a,ll b,ll& x,ll& y)
 34 {
 35     if(!b)
 36     {
 37         x = 1,y=0;
 38         return a;
 39     }
 40     ll d = exgcd(b,a%b,y,x);
 41     y-=a/b*x;
 42     return d;
 43 }
 44 ll Get_ans()
 45 {
 46     ll x,y,z = 0;
 47     for(int i=1;i<=C;i++)
 48     {
 49         ll tmp = res/X[i];
 50         ll d = exgcd(tmp,X[i],x,y);
 51         x = (x%X[i]+X[i])%X[i];
 52         z = (z+m[i]*tmp*x%res)%res;
 53     }
 54     return z;
 55 }
 56 void dfs(int c)
 57 {
 58     if(c>C)
 59     {
 60         ans.push_back(Get_ans());
 61         return ;
 62     }
 63     for(int i=1;i<=k[c];i++)
 64     {
 65         m[c] = Y[c][i];
 66         dfs(c+1);
 67     }
 68 }
 69 void solve_2()
 70 {
 71     for(int q=0;T;q++)
 72     {
 73         for(int j=1;j<=k[best];j++)
 74         {
 75             ll tmp = X[best]*q+Y[best][j];//假设tmp为一个解 
 76             if(tmp<=0) continue;
 77             bool ok = 1;
 78             for(int i=1;i<=C;i++)
 79             {
 80                 if(i==best) continue;
 81                 ll rest = tmp%X[i];
 82                 if(!s[i].count(rest)) { ok=0; break;}
 83             }
 84             if(ok)
 85             {
 86                 printf("%lld\n",tmp);
 87                 T--;
 88                 if(!T) break;
 89             }
 90         }
 91     }
 92 }
 93 void solve_1()
 94 {
 95     dfs(1);
 96     sort(ans.begin(),ans.end());
 97     for(int i=0;T;i++)
 98     {
 99         for(int j=0;j<ans.size();j++)
100         {
101             ll tmp = i*res+ans[j];//防止所有枚举后的解不够T个 
102             if(tmp>0)
103             {
104                 printf("%lld\n",tmp);
105                 if(--T==0) break;
106             }
107         }
108     }
109 }
110 int main()
111 {
112 //    freopen("in.txt","r",stdin);
113     while(scanf("%d%d",&C,&T)&&(C+T))
114     {
115         Update();
116         inits();
117         if(tot<M) solve_1();
118         else solve_2();
119         puts("");
120     }
121     return 0;
122 }

 

posted @ 2021-01-28 15:41  acmloser  阅读(89)  评论(0编辑  收藏  举报