Description
for (variable = A; variable != B; variable += C) statement;
Input
Output
Sample Input
3 3 2 16 3 7 2 16 7 3 2 16 3 4 2 16 0 0 0 0
Sample Output
0 2 32766 FOREVER
题目大意:根据题意求出循环次数,若死循环输出FOEVER
思路:通过公式的变形可得C*x=(B-A)%2^k转化为模的线性方程
</pre><pre name="code" class="cpp">#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #define LL long long #define inf 0x3f3f3f3f using namespace std; LL x,y; LL exgcd(LL a,LL n) { LL t,d; if(!n)//已知方程a*x+b*y=gcd(a,b){ 公式一 };这里n-->b { x=1;y=0;//当n==0,a*x=gcd(a,0)=a;所以x=1,y=0; return a; }//否则继续进行 d=exgcd(n,a%n);//当再次递归时gcd(a,n)=gcd(n,a%n),将其带入公式1中变形可得 //b*x1+(a%b)*y1==b*x1+(a-(a/b)*b)*y1==a*y1+b*(x1-(a/b)*y1),最终得到ax+by==a*y1+b*(x1-(a/b)*y1) t=x;//既可以得到x=y1(y),y1(y)=x1-(a/b)*y1 x=y; y=t-a/n*y; return d; } int main() { LL n,k,i,j,A,B,C,a,b,d; while(~scanf("%lld%lld%lld%lld",&A,&B,&C,&k)) { if(A==0&&B==0&&C==0&&k==0)//已知拓展的欧几里得公式为ax+by=gcd(a,b); break; n=(1LL<<k);//若不再1后加LL会WA- -! a=C;b=B-A;//根据题意,可以推得C*x=(A-B)%2^k;此方程为模线性方程即a*x=b%n; d=exgcd(a,n); if(b%d)//模线性方程有解的充要条件是b%(gcd(a,n))==0 { puts("FOREVER"); continue; }//如果线性方程 x=x*(b/d)%n;//方程a*x=b%n的最小解 x=(x%(n/d)+(n/d))%(n/d);// x%(n/gcd(a,n))使解落到区间-n/gcd(a,n)~n/gcd(a,n), //再加上n/gcd(a,n)使解在区间0~2*n/gcd(a,n), //再模上n/gcd(a,n),则得到最小整数解 printf("%lld\n",x); } return 0; }
思路:扩展的欧几里得为ax+by=c => 一、ax+by=GCD(a,b) , 通过此题二、Cx+my=B-A,同时 我们还可以得到公式 Cx+A+y2^k=B 即Cx=(B-A)%2^k
我们可以吧b=(B-A); 通过ex扩展GCD公式求出x,注意这里的x不是公式二Cx+my=b中的x,若想由公式一中的推出公式二可以将公式一同时乘b/GCD(C,2^k);
这就是为什么x=x*(b/GCD()).还有x取得范围问题,(x0+k*(m/GCD()) ,y0+k*(C/GCD()));(T_T终于明白了!!!!!)
#include<map> #include<queue> #include<cmath> #include<iostream> #include<cstdio> #include<stack> #include<cstring> #include<algorithm> #define LL __int64 #define inf 0x3f3f3f3f const double PI=acos(-1.0); using namespace std; void ex(LL a,LL b,LL &d,LL &x,LL &y){ if(!b){ d=a,x=1,y=0; } else{ ex(b,a%b,d,y,x); y-=x*(a/b); } } int main(){ LL b,B,A,C,n,k,d,x,y; while(~scanf("%I64d%I64d%I64d%I64d",&A,&B,&C,&k)){ if(!A&&!B&&!C&&!k) break; n=(1LL<<k); b=B-A; ex(C,n,d,x,y); if(b%d==0){ x=x*(b/d)%n; x=(x%(n/d)+n/d)%(n/d); printf("%I64d\n",x); } else{ puts("FOREVER"); } } return 0; }