accoders10151语法基础 题解
10.3 国庆集训第一题 传送门
题目描述
PYB说:七夕节的oier,一定要记得码代码,代码中循环绝对是最最最基础的东西,C++的循环语句有下面这种格式:
for (变量x= A;变量x!= B;变量x+= C) 循环语句;
上面的循环一开始设置循环变量x的初始值为A,当判断循环变量x的值不等于B时执行后面的循环语句,再将循环变量x的值加上C接着判断。作为优秀的oier,你肯定能很快算出对于给定的A、B、C的值,循环语句被执行多少次。假定所有的算术计算都在一个k位无符号整数类型内进行(0 <=x< 2k),超过2k则对2k取模。
输入格式
输入包含多个测试数据。每个测试数据占一行,包括四个用空格隔开的整数A、B、C、k。整数k(1<= k<= 32)是循环控制变量的位数,A、B、C(0 <= A、B、C < 2k)是循环中参数。
输入数据最后一行以四个0结束。
输出格式
对应输入文件中每测试数据输出一行。对每个测试数据,要么输出一个整数表示循环语句被执行的次数,要么输出字符串“FOREVER”表示循环语句永远不会停止。
样例输入
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
样例输出
0
2
32766
FOREVER
提示
本题采用文件输入输出,文件名为loop.in和loop.out。
题解
由题意循环终止时i=B,此时有(A+Cx)mod 2k=B,即问题可以转化为求不定方程Cx-2ky=B-A中x的最小值。
注意B-A并不一定是gcd(C,2k),而且x并不能保证是最小值甚至正值,需手动更新。
若B-A不能整除gcd(C,2k)则无解。
注意a为0不代表四个数均为0。
AC代码
#include<bits/stdc++.h> #pragma GCC optimize(2) typedef long long ll; using namespace std; ll a,b,c,d,tem[33]={1}; inline ll gcd(ll a,ll b){ if(b==0) return a; return gcd(b,a%b); } void exgcd(ll a,ll b,ll &x,ll &y,ll sum){//exgcd求解的是Ax+By=gcd(A,B) if(b==0){ x=sum/a,y=0; return; } ll tx,ty; exgcd(b,a%b,tx,ty,sum); x=ty,y=tx-a/b*ty; return; } int main(){ freopen("loop.in","r",stdin); freopen("loop.out","w",stdout); for(int i=1;i<=32;i++) tem[i]=tem[i-1]*2; while(cin>>a){ ll x,y; scanf("%lld%lld%lld",&b,&c,&d); if(d==0) break; ll te=gcd(c,tem[d]),m=(b-a)/te; if((b-a)%te!=0){ printf("FOREVER\n"); continue; } exgcd(c,tem[d],x,y,te); x=(x*m)%(tem[d]/te); //将x更新为最靠近0的解 while(x>0) x-=(tem[d]/te); while(x<0) x+=(tem[d]/te); //将小于0的x取正 printf("%lld\n",x); } }