accoders10151语法基础 题解

10.3 国庆集训第一题  传送门

题目描述

PYB说:七夕节的oier,一定要记得码代码,代码中循环绝对是最最最基础的东西,C++的循环语句有下面这种格式:

for (变量x= A变量x!= B变量x+= C) 循环语句;

上面的循环一开始设置循环变量x的初始值为A,当判断循环变量x的值不等于B时执行后面的循环语句,再将循环变量x的值加上C接着判断。作为优秀的oier,你肯定能很快算出对于给定的ABC的值,循环语句被执行多少次。假定所有的算术计算都在一个k位无符号整数类型内进行0 <=x< 2k),超过2k则对2k取模。

输入格式

输入包含多个测试数据。每个测试数据占一行,包括四个用空格隔开的整数ABCk。整数k1<= k<= 32)是循环控制变量的位数,ABC0 <= ABC < 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.inloop.out

题解

由题意循环终止时i=B,此时有(A+Cxmod 2k=B,即问题可以转化为求不定方程Cx-2ky=B-Ax的最小值。

注意B-A并不一定是gcd(C,2k),而且x并不能保证是最小值甚至正值,需手动更新。

B-A不能整除gcd(C,2k)则无解。

注意a0不代表四个数均为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);
    }
}

 

posted @ 2021-10-03 20:26  key4127  阅读(180)  评论(0)    收藏  举报