CF1427E Xum
https://www.luogu.com.cn/problem/CF1427E
题目大意
一开始黑板上有一个正整数,每次你可以选定黑板上已有的两个正整数 ,将两个数的和或两个数的异或写在黑板上,最终目标是将1写在黑板上。
题解
一道非常巧妙的构造题。
考虑我们如何最终写出\(n\)这个数来,那么这样一定是\(x \oplus (x+1)\),并且这里的\(x\)是偶数。
那么既然我们只能用加法去凑这两个数,那么我们可以想到用二元方程来解决\(ax+by=1\) 但这个方程有解的前提是\(gcd(x,y)=1\)
然后发现\(x\)是奇数,所以我们可以无端联想到,我们将\(x\)左移\(bit-1\)位,再让它去异或\(x\)它会变成\(x<<(bit-1)\oplus x+x-(1<<bit)\)然后我们惊讶的发现它和\(x\)是互质的!
那么我们就可以用扩欧找到一组解,这时可能会出现奇偶顺序相反的情况,但是我们的\(x\)和\(y\)都是奇数,我们可以微调一下。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,ct,x,y,as,g;
inline ll rd(){
ll x=0;char c=getchar();bool f=0;
while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x;
}
inline void work(ll x,ll y){
ll ans=0;
while(y){
if(y&1){
if(ans)printf("%lld + %lld\n",ans,x);
ans+=x;
}
printf("%lld + %lld\n",x,x);
x<<=1;
y>>=1;
}
}
inline void work1(ll x,ll y){
ll ans=0;
while(y){
if(y&1){
if(ans)as++;
ans+=x;
}
as++;
x<<=1;
y>>=1;
}
}
inline void exgcd(ll a,ll b){
if(!b){
x=1;
y=0;
g=y;
return;
}
exgcd(b,a%b);
ll k=x;x=y;y=k-a/b*x;
}
inline void prework(){
ll num=n;
while(num)num>>=1,ct++;
ct--;
work1(n,1<<ct);
ll num1=(n<<ct)^n;
as++;
exgcd(n,num1);
int T;
x=x%num1+num1;y=(1-x*n)/num1;
if (y&1) x+=num1,y-=n;
work1(n,abs(x));
work1(num1,abs(y));
as++;
cout<<as<<endl;
}
int main(){
n=rd();
prework();
ll num=n;
ct=0;
while(num)num>>=1,ct++;
ct--;
work(n,(1<<ct));
ll num1=(n<<ct)^n;
printf("%lld ^ %lld\n",n<<ct,n);
exgcd(n,num1);
int T;
x=x%num1+num1;y=(1-x*n)/num1;
if (y&1) x+=num1,y-=n;
work(n,abs(x));
work(num1,abs(y));
printf("%lld ^ %lld\n",n*abs(x),num1*abs(y));
return 0;
}