题目链接: http://www.bnuoj.com/v3/problem_show.php?pid=20172
题目大意:有C个模方程,每个方程可能有k余数,求最小的S个解。
解题思路:
看见模方程就想到中国剩余定理,然后看下确定的方程情况。
由乘法原理,共有II ki 种情况,即求解II ki 次。k比较大时基本完蛋。
其实解模方程还有一种暴力方法,就是选定一个模方程,令t=0,1...., n=t*LCM+余数(n一定要大于0)
通过t不断增大这种迭代方式从小到大创造一些可能解n,然后去测试其它方程,看余数对不对。
如果余数全对,那么就找到了一个解。否则就砍掉。
因为测试是很快的,大部分数据一开始就被砍了,所以k比较大时速度非常快。
毕竟上面是看RP的暴力,所以设定一个分界(10000),如果II ki <10000 ,那么还是通过中国剩余定理来求解,复杂度O(n)。
方法就是DFS枚举出C个余数情况,然后求解。
由于求出的全是最小整数解,S比较大时,剩余定理的解可能不足,这时候从小到大每个值加M的倍数凑出更大的解。
#include "cstdio" #include "set" #include "vector" #include "algorithm" using namespace std; #define LL long long #define LIMIT 10000 int C,S,s; LL m[15],k[15],y[15][105],a[15],M; set<LL> value[15]; vector<LL> ans; void solve_violence(int bc) { for(int i=1;i<=C;i++) { value[i].clear(); if(i!=bc) for(int j=1;j<=k[i];j++) value[i].insert(y[i][j]); } for(int t=0;S!=0;t++) { for(int i=1;i<=k[bc];i++) { LL n=t*m[bc]+y[bc][i]; if(!n) continue; bool ok=true; for(int j=1;j<=C;j++) { if(j==bc) continue; if(!value[j].count(n%m[j])) {ok=false;break;} } if(ok) {printf("%lld\n",n);if(--S==0) return;} } } } LL ex_gcd(LL a,LL b,LL &x,LL &y) { if(a==0&&b==0) return -1; if(b==0) {x=1;y=0;return a;} LL d=ex_gcd(b,a%b,y,x); y-=a/b*x; return d; } LL solve_china() { LL res=0;M=1; for(int i=1;i<=C;i++) M*=m[i]; for(int i=1;i<=C;i++) { LL w=M/m[i],x,y; ex_gcd(m[i],w,x,y); y=(y*w%M+M)%M; res=(res+y*a[i])%M; } return res; } void dfs(int dep) { if(dep>C) { ans.push_back(solve_china()); return; } for(int i=1;i<=k[dep];i++) { a[dep]=y[dep][i]; dfs(dep+1); } } int main() { //freopen("in.txt","r",stdin); while(scanf("%d%d",&C,&S)&&C) { int bestc=1;ans.clear();s=S;M=1; LL tot=1; for(int i=1;i<=C;i++) { scanf("%lld%lld",&m[i],&k[i]); tot*=k[i]; if(k[i]*m[bestc]<k[bestc]*m[i]) bestc=i; for(int j=1;j<=k[i];j++) scanf("%lld",&y[i][j]); sort(y[i]+1,y[i]+1+k[i]); } if(tot<LIMIT) { dfs(1); sort(ans.begin(),ans.end()); for(int t=0;S!=0;t++) for(int i=0;i<ans.size();i++) { LL n=t*M+ans[i]; if(n>0) { printf("%lld\n",n); if(--S==0) break; } } } else solve_violence(bestc); printf("\n"); } }
neopenx | 445520 | 20172 | Accepted | GNU C++ | 26 ms | 2223 B | 2015-02-06 23:10:03 |
时间: 2024-11-03 05:30:24