51nod1352(exgcd)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1352
题意:中文题诶~
思路:exgcd
显然题目可以描述为:求a*x+b*y=n+1中满足 1 <= x,y <=n 的解数,
可以先通过exgcd求出一组a*x+b*y=gcd(a, b)的解 x1, y1,那么对应的a*x+b*y=n+1的解就是x1*(n/gcd(a, b)), y1*(n/(gcd(a, b)),
若能求出最小的x解的话,则每隔lcm(a, b), 隔lcm(a, b)出现一组满足条件的解,所以有ans=(n-1-x*a)/lcm(a,b) + 1;
先令x=x1%b,要尽量使x小,所以将大于b的部分放到b*y中去;
令temp=x*a, cc=lcm(a, b)
则有:
while(temp<1){
temp+=cc;
}
while(temp>0){
temp-=cc;
}
temp+=cc;// 第一个大于0的a*x
将其直接化为公式计算:
if(temp<1){
k=ceil(double(1-temp)/cc);
temp+=cc*k;
}else{
k=(temp-1)/cc;
temp-=cc*k;
}
答案也就显而易见了,注意中间可能会爆int....
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #define ll long long 5 using namespace std; 6 7 int exgcd(ll a, ll b, ll& d, ll& x, ll& y){ 8 if(b==0){ 9 x=1, y=0, d=a; 10 }else{ 11 exgcd(b, a%b, d, y, x); 12 y-=(a/b)*x; 13 } 14 } 15 16 int main(void){ 17 int t; 18 ll n, a, b; 19 scanf("%d", &t); 20 while(t--){ 21 scanf("%lld%lld%lld", &n, &a, &b); 22 ll x, y, d; 23 exgcd(a, b, d, x, y); 24 if((++n)%d){ //a*x+b*y=c 当且仅当c=k*gcd(a,b)时有整数解 25 printf("0\n"); 26 continue; 27 } 28 x=x*(n/d)%b; //得到a*x+b*y=n+1的解,若x>b,将大于b的部分放到y*b中 29 ll cc=a*b/d; //lcm(a,b) 30 ll temp=x*a; 31 // while(temp<1){ 32 // temp+=cc; 33 // } 34 // while(temp>0){ 35 // temp-=cc; 36 // } 37 // temp+=cc;// 第一个大于0的a*x 38 ll k; 39 if(temp<1){ 40 k=ceil(double(1-temp)/cc); 41 temp+=cc*k; 42 }else{ 43 k=(temp-1)/cc; 44 temp-=cc*k; 45 } 46 if(temp>=n){ 47 printf("0\n"); 48 }else{ 49 printf("%lld\n", (n-temp-1)/cc+1);//前面给n加了1,但求出的b*y要<=n 50 } 51 } 52 return 0; 53 }
我就是我,颜色不一样的烟火 --- geloutingyu