Date:2022.04.13
题意描述:
对于 C 语言的循环语句,形如:
for (variable = A; variable != B; variable += C)
statement;
请问在 k 位存储系统中循环几次才会结束。
若在有限次内结束,则输出循环次数。否则输出死循环。
输入格式
多组数据,每组数据一行四个整数 A,B,C,k。
读入以 0 0 0 0 结束。
输出格式
若在有限次内结束,则输出循环次数。
否则输出 FOREVER。
数据范围
1≤k≤32,
0≤A,B,C<2^k
输入样例:
3 3 2 16
3 7 2 16
7 3 2 16
3 4 2 16
0 0 0 0
输出样例:
0
2
32766
FOREVER
思路:首先k 位存储系统即代表只取最后k位,即
(
a
+
x
∗
c
)
%
2
k
=
=
b
%
2
k
(a+x*c)\%2^k==b\%2^k
(a+x∗c)%2k==b%2k。
x
∗
c
+
y
∗
2
k
≡
b
−
a
【
m
o
d
2
k
】
(
I
)
x*c+y*2^k \equiv b-a 【mod 2^k】(I)
x∗c+y∗2k≡b−a【mod2k】(I)
问题转换为求满足线形同余方程的一个正整数解
x
x
x。
e
x
g
c
d
(
c
,
2
k
,
x
,
y
)
exgcd(c,2^k,x,y)
exgcd(c,2k,x,y)求出
x
∗
c
+
y
∗
2
k
≡
g
c
d
(
c
,
2
k
)
【
m
o
d
2
k
】
(
I
I
)
x*c+y*2^k \equiv gcd(c,2^k) 【mod2^k】(II)
x∗c+y∗2k≡gcd(c,2k)【mod2k】(II)。
我们假设
(
I
I
)
(II)
(II)的特解为{
x
0
,
y
0
x_0,y_0
x0,y0}。
由此:
①若
g
c
d
(
c
,
2
k
)
∤
(
b
−
a
)
gcd(c,2^k)\nmid(b-a)
gcd(c,2k)∤(b−a):线性方程组(I)无解。
②若
g
c
d
(
c
,
2
k
)
∣
(
b
−
a
)
gcd(c,2^k)\mid(b-a)
gcd(c,2k)∣(b−a):线性方程组(I)有解。
其中,一组特解是
(
I
I
)
(II)
(II)的特解扩大若干倍,即:
{
x
1
=
(
b
−
a
)
g
c
d
(
c
,
2
k
)
∗
x
0
;
y
1
=
(
b
−
a
)
g
c
d
(
c
,
2
k
)
∗
y
0
;
\left\{ \begin{array}{lr} x_1=\frac{(b-a)}{gcd(c,2^k)}*x_0; \\ y_1=\frac{(b-a)}{gcd(c,2^k)}*y_0; \end{array} \right.
{x1=gcd(c,2k)(b−a)∗x0;y1=gcd(c,2k)(b−a)∗y0;
但我们要找
x
>
=
0
x>=0
x>=0,假设找到的是
x
2
x_2
x2,则
x
2
x_2
x2必满足:
{
x
2
=
x
1
+
k
∗
2
k
g
c
d
(
c
,
2
k
)
;
y
2
=
y
1
−
k
∗
c
g
c
d
(
c
,
2
k
)
;
\left\{ \begin{array}{lr} x_2=x_1+k*\frac{2^k}{gcd(c,2^k)}; \\ y_2=y_1-k*\frac{c}{gcd(c,2^k)}; \end{array} \right.
{x2=x1+k∗gcd(c,2k)2k;y2=y1−k∗gcd(c,2k)c;
我们不妨就求个最小的
x
2
>
0
x_2>0
x2>0,因此
x
2
(
m
i
n
)
=
x
1
%
2
k
g
c
d
(
c
,
2
k
)
x_{2(min)}=x1\%\frac{2^k}{gcd(c,2^k)}
x2(min)=x1%gcd(c,2k)2k,但注意
x
2
x_2
x2可能为负数,取模为负数,因此
x
2
(
m
i
n
)
=
(
x
1
%
2
k
g
c
d
(
c
,
2
k
)
+
2
k
g
c
d
(
c
,
2
k
)
)
%
2
k
g
c
d
(
c
,
2
k
)
x_{2(min)}=(x1\%\frac{2^k}{gcd(c,2^k)}+\frac{2^k}{gcd(c,2^k)})\%\frac{2^k}{gcd(c,2^k)}
x2(min)=(x1%gcd(c,2k)2k+gcd(c,2k)2k)%gcd(c,2k)2k。
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
typedef long long LL;
LL k,a,b,c;
LL qmi(LL a,LL k)
{
LL res=1;
while(k)
{
if(k&1) res=res*a;
a=a*a;k>>=1;
}
return res;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
LL d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main()
{
while(cin>>a>>b>>c>>k,a||b||c||k)
{
LL x,y,kk=qmi(2,k);
LL d=exgcd(c,kk,x,y);
if((b-a)%d) cout<<"FOREVER\n";
else
{
x*=(b-a)/d;kk/=d;
cout<<(x%kk+kk)%kk<<'\n';
}
}
return 0;
}