【中国剩余定理 && 枚举 && 思维】UVA 11754 Code Feat
2017-10-19 19:49
411 查看
Problem Decription
有一个正整数N满足C个条件,每个条件都形如“它除以X的余数在集合{y1, y2, …, yk}中”,所有条件中的X两两互素,你的任务是找出最小的S个解。
思路:
“除以X的余数在集合{Y1, Y2, …, Yk}中”这个条件很不好处理。如果我们知道这个余数具体是Y1,Y2,…Yk中的哪一个,问题就会简单很多。一种容易想到的方法是枚举每个集合中取那个元素,跑一个dfs()枚举所有情况。
上述方法如果所有k的乘积很大时这种方法会很慢,此外我们有另一种方法,直接枚举x。找出个k/X最小的条件,因为X很大,k很小的时候。按照t = 0, 1, 2, …的顺序枚举所有的tX + Yi(相同的t按照从小到大的顺序枚举Yi),看看是否满足条件。因为所有k的乘积很大,这个算法很快就能找到解。
单单只用第二种方法会超时,如果想到两种方法结合,这是一个核心点
有一个正整数N满足C个条件,每个条件都形如“它除以X的余数在集合{y1, y2, …, yk}中”,所有条件中的X两两互素,你的任务是找出最小的S个解。
思路:
“除以X的余数在集合{Y1, Y2, …, Yk}中”这个条件很不好处理。如果我们知道这个余数具体是Y1,Y2,…Yk中的哪一个,问题就会简单很多。一种容易想到的方法是枚举每个集合中取那个元素,跑一个dfs()枚举所有情况。
上述方法如果所有k的乘积很大时这种方法会很慢,此外我们有另一种方法,直接枚举x。找出个k/X最小的条件,因为X很大,k很小的时候。按照t = 0, 1, 2, …的顺序枚举所有的tX + Yi(相同的t按照从小到大的顺序枚举Yi),看看是否满足条件。因为所有k的乘积很大,这个算法很快就能找到解。
单单只用第二种方法会超时,如果想到两种方法结合,这是一个核心点
#include<bits/stdc++.h> using namespace std; #define LL long long int S, C, x[20], Size[20], y[20][150], temp[20]; LL tot, M; set<int> q[15]; vector<LL> ans; void extend_gcd(LL a, LL b, LL &x, LL &y)//扩展欧几里得,求x, y { if(!b){ x = 1; y = 0; }else{ extend_gcd(b, a%b, y, x); y -= x*(a/b); } } void CRT(int a[], int m[], int n)//中国剩余定理求x { LL M = 1, x, y; for(int i = 0; i < n; i++) M *= m[i]; LL ret = 0; for(int i = 0; i < n; i++) { LL tm = M/m[i]; extend_gcd(tm, m[i], x, y); ret = (ret + tm*x*a[i]) % M; } ans.push_back((ret+M)%M); } void dfs(int u)//dfs枚举所有情况,每种情况存入temp[]数组中 { if(u == S) { CRT(temp, x, S); return; } for(int i = 0; i < Size[u]; i++) { temp[u] = y[u][i]; dfs(u+1); } } void solve(int id)//id是k/x最小的,枚举t/x + yi看看其他条件满足与否 { int i, j, k; for(i = 0; i < S; i++) { q[i].clear(); if(i == id) continue; for(j = 0; j < Size[i]; j++)//其他的用set存起来,后面可以很快查询是否存在y[i][j] q[i].insert(y[i][j]); } LL N; for(i = 0; ; i++) { for(j = 0; j < Size[id]; j++) { N = (LL)i*x[id] + y[id][j];//枚举N if(!N) continue; for(k = 0; k < S; k++) { if(k == id) continue; if(!q[k].count(N%x[k])) break;//不满足退出循环 } if(k == S){//都满足,输出 printf("%lld\n", N); if(!--C) return; } } } } int main() { int i, j; while(~scanf("%d %d", &S, &C)) { if(!S && !C) break; int xx = 1, SS = 100, Minid; tot = 1; M = 1; for(i = 0; i < S; i++) { scanf("%d %d", &x[i], &Size[i]); M *= x[i];//所有的x的乘积 tot *= (LL)Size[i];//所有的k的乘积 if(Size[i]*xx < SS*x[i]) {//求出最小的k/x 对应的 下标 SS = Size[i]; xx = x[i]; Minid = i; } for(j = 0; j < Size[i]; j++) scanf("%d", &y[i][j]); sort(y[i], y[i] + Size[i]);//排序从小到大,后面枚举的时候优先小的 } if(tot <= 10000) {//dfs && 中国剩余定理 ans.clear(); dfs(0); sort(ans.begin(), ans.end()); for(i = 0; C; i++) { for(j = 0; j < ans.size(); j++) { LL N = i*M + ans[j]; if(N > 0){ printf("%lld\n", N); if(!--C) break; } } } } else solve(Minid);//k太大,枚举t*X + Yi printf("\n"); } return 0; }
相关文章推荐
- UVa 11754 (中国剩余定理 枚举) Code Feat
- UVa 11754 - Code Feat (中国剩余定理 枚举)
- uva11754 - Code Feat 枚举 中国剩余定理
- UVA 11754 Code Feat 中国剩余定理+普通枚举
- uva 11754 Code Feat 中国剩余定理
- UVA 11754 Code Feat (枚举,中国剩余定理)
- uva 11754 - Code Feat(中国剩余定理+暴力)
- UVA 11754 (暴力+中国剩余定理)
- UVA - 11754 Code Feat (中国剩余定理 + 分类枚举)
- UVA 11754 Code Feat 中国剩余定理+暴力
- uva 11754 中国剩余定理
- 【中国剩余定理】POJ 1006 & HDU 1370 Biorhythms
- hdu-1370(中国剩余定理余数互质)&&hdu-1573(中国剩余定理余数不互质)
- poj1006 中国剩余定理&&中国剩余定理解析
- 【中国剩余定理】POJ 1006 & HDU 1370 Biorhythms
- zoj 1160 && 中国剩余定理
- 扩展的欧几里得&中国剩余定理
- exgcd&&中国剩余定理专题练习
- POJ 2891 扩展欧几里德&&中国剩余定理
- HDU5768:Lucky7(中国剩余定理 & 容斥)