zoukankan      html  css  js  c++  java
  • 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
    ",ans,x);
    			ans+=x;
    		}
    		printf("%lld + %lld
    ",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<<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*abs(x),num1*abs(y));
    	return 0;
    }
    
  • 相关阅读:
    luogu 2627 修剪草坪
    luogu2746 [USACO5.3]校园网Network of Schools
    luogu 1558 色板游戏
    luogu 2827 蚯蚓
    POJ 2559 Largest Rectangle in a Histogram
    luogu 1886 滑动窗口
    luogu 1090 合并果子
    uva 11572
    uva 12626
    uva 10222
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/13965918.html
Copyright © 2011-2022 走看看