2020.11.23
解法
题目只要求求出 (C) 的值,它就提示我们 (C) 和 (A)、(B) 的值没有太大关系。照着这个思路我们把 (A) (B) 合并一下,搞成二元组。对 (A+Bleq C),((A+B,C) o(2(A+B),C-(A+B))),对 (A+B>C),((A+B,C) o((A+B)-C,2C))。我们发现 (AB) 始终可以并在一起,干脆直接记为 (D)。对 (Dleq C),((D,C) o(2D,C-D)),对 (D>C),((D,C) o(D-C,2C))。这两个式子有很大的共性,可以说成是对称的。
while(k--){
if(a<=c) c-=a,a<<=1;
else a-=c,c<<=1;
}
(然而这波并没有任何的加成效果)
再观察,发现 (2C) 可以写成 (C+C),又左边是 (D-C),那么二元组内的和是没有变的,始终为 (A+B+C)。(这大概又提示我们和模运算有关?)
这个暴力不能优化的原因在于其中一条语句执行了一定次数,就会跳过去执行另一条语句。实际上是交换 (A) 和 (C) 的值(因为式子是对称的)。大胆尝试,如果到了临界点不交换会发生什么,令 (S=C+D) ,那么 (C+C=C+(S-D)=(C-D)+S) 和 (D-C=D-(S-D)=2D-S)。我们发现这交不交换的本质其实是一样的,只不过区别于有没有加上一个 (S) 即 (A+B+C),所以可以一直乘 (2),然后对 (S) 取模即可。
#include<stdio.h>
#define ll long long
#define N 100007
inline int read(){
int x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
ll a,c,Mod;
int T,k;
ll qpow(ll x,ll y){
ll ret=1,cnt=0;
while(y>=(1LL<<cnt)){
if(y&(1LL<<cnt)) ret=(ret*x)%Mod;
x=(x*x)%Mod,cnt++;
}
return ret;
}
int main(){
// freopen("easy.in","r",stdin);
// freopen("easy.out","w",stdout);
T=read();
while(T--){
a=read()+read(),c=read(),k=read();
Mod=a+c;
printf("%lld
",c*qpow(2LL,k)%Mod);
}
}