CF1427E Xum

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;
}
posted @ 2020-11-12 19:57  comld  阅读(217)  评论(0编辑  收藏  举报