[codevs1213]解的个数 二分 + exgcd
2017-11-02 20:15
232 查看
题目←
扩欧,求不定方程解的个数
我们已经知道通解x0 = x +- (b/gcd(a,b))*t,那只要知道有多少个t使x在题目给定的范围中就行了
但还有y
怎么办?求交集!
分别二分确定在x取值范围内合法的t的范围和在y取值范围内合法的t的范围
然后交一下
值得一提的是,对于同一个t,由exgcd求出的x,y而找到的一组通解为
x + (b/gcd(a,b)) * t,y - (a/gcd(a,b)) * t
或
x - (b/gcd(a,b)) * t,y + (a/gcd(a,b)) * t
当a,b同号时,应注意t是互为相反数的
对此把某一组解的范围 *= -1就好了
还有一种解法是划定范围+枚举,时间上不如二分但代码更简洁
注意特判最后几组a,b == 0的数据……
扩欧,求不定方程解的个数
我们已经知道通解x0 = x +- (b/gcd(a,b))*t,那只要知道有多少个t使x在题目给定的范围中就行了
但还有y
怎么办?求交集!
分别二分确定在x取值范围内合法的t的范围和在y取值范围内合法的t的范围
然后交一下
值得一提的是,对于同一个t,由exgcd求出的x,y而找到的一组通解为
x + (b/gcd(a,b)) * t,y - (a/gcd(a,b)) * t
或
x - (b/gcd(a,b)) * t,y + (a/gcd(a,b)) * t
当a,b同号时,应注意t是互为相反数的
对此把某一组解的范围 *= -1就好了
还有一种解法是划定范围+枚举,时间上不如二分但代码更简洁
注意特判最后几组a,b == 0的数据……
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL A,B,C,P,Q,R,S; int n; LL a,b,c,m,x,y,G; LL Gcd(LL a,LL b){ return b ? Gcd(b,a%b) : a; } void exgcd(LL a,LL b){ if(!b){ x = 1; y = 0; return; } exgcd(b,a%b); LL tmp = y; y = x - (a/b)*y; x = tmp; } LL lim1,lim2,lim3,lim4,liml,limr,T; int main(){ cin >> T; while(T --){ scanf("%lld%lld%lld%lld%lld%lld%lld",&A,&B,&C,&P,&Q,&R,&S); if(!A && !B){ if(C == 0){ liml = max(P,R); limr = min(Q,S); if(limr < liml)printf("0\n"); else printf("%lld\n",(Q - P + 1)*(S - R + 1)); } else printf("0\n"); continue; } G = Gcd(A,B); C *= -1; if(C%G){ printf("0\n"); continue; } a = A/G;b = B/G;c = C/G; exgcd(a,b); x *= c;y *= c; if(b < 0)b *= -1; if(a < 0)a *= -1; LL l = -100000000LL,r = 100000000LL; while(r - l > 1){ LL mid = r + l >> 1; if(x + b*mid < P)l = mid; else r = mid; } lim1 = r; l = -100000000LL;r = 100000000LL; while(r - l > 1){ LL mid = r + l >> 1; if(x + b*mid <= Q)l = mid; else r = mid; } lim2 = l; l = -100000000LL;r = 100000000LL; while(r - l > 1){ LL mid = r + l >> 1; if(y + a*mid < R)l = mid; else r = mid; } lim3 = r; l = -100000000LL;r = 100000000LL; while(r - l > 1){ LL mid = r + l >> 1; if(y + a*mid <= S)l = mid; else r = mid; } lim4 = l; if((A > 0) == (B > 0)){ lim3 *= -1; lim4 *= -1; swap(lim3,lim4); } liml = max(lim1,lim3); limr = min(lim2,lim4); printf("%lld\n",max(0LL,limr - liml + 1)); //cout << a << b << endl; } }
相关文章推荐
- codevs 1213 解的个数
- codevs1213(扩欧,求区间内解的数量)
- [codevs1213]解的个数(数论,扩欧)
- Codevs1213 解的个数
- codevs1213 解的个数-----------数论/扩展欧几里得
- CodeVS 1213 解的个数
- 解的个数(codevs 1213)
- 扩展gcd codevs 1213 解的个数
- 潜伏者(codevs 1171)
- codevs1922(二分图最大独立集)
- [网络流24题][CODEVS1915]分配问题(网络流)
- crossplatform---Node.js Applications with VS Code
- 【codevs2293】山海经 线段树
- 【CodeVS】【2004年NOIP全国联赛提高组】1057 津津的储蓄计划
- codevs 1021 玛丽卡
- vs code vue模板创建
- Codevs 1961 躲避大龙
- 自使用移动端rem适配--并且vscode-px自动转化成rem
- vscode 常用快捷键
- Codevs 1010 过河卒== 洛谷 1002