Code Feat UVA - 11754
基本是抄lnj老师的代码,这种方法本蒟蒻就是被打死都想不出来= =
错误思路:
枚举每一种组合,代入模板求解,将解排序输出
这种思路主要错在两个地方:
- k<=100,C<=9.最多有1009种枚举方式.TLE
- 枚举的组合数<要求输出的解数.此时我们需要对解+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 }