zoukankan      html  css  js  c++  java
  • CF1408F Two Different

    Pro:

    Sol:
    这种构造题没有什么捷径

    就是多手玩,多总结

    考虑n=2^k的时候

    我们可以用一个简单的分治来构造出合法解

    可以很容易的得到2^k个相同的数字

    可以总结出这样一个性质
    (2^a)(x)(2^a)(y)可以合并成(2^{a+1})(xy)

    考虑n=2^k+c的时候怎么做

    把c拆解为(2^a + 2^b + 2^c +....)

    这个时候我们仍按照刚才分治合并的策略来执行

    但这个时候我们会发现由于a b c不连续

    所以向上合并的时候会缺少元素

    怎么办呢?

    不如直接从2^k借一些过来!

    我们可以事先预处理是的2^k个元素合并为同一个数字

    当处理c不够用是直接从2^k借就可以了!

    又由于c<2k所以,2k一定是够用的!

    用n=13举个例子
    13=8+5

    5=1+4

    预处理为这种形式

    a bbbb

    向2^k借一个1

    aa bbbb

    向2^k借一个2

    aaaa bbbb

    合并

    aaaaaaaa

    #include<bits/stdc++.h>
    #define N 550000
    #define eps 1e-7
    #define inf 1e9+7
    #define db double
    #define ll long long
    #define ldb long double
    #define ull unsigned long long
    using namespace std;
    inline int read()
    {
    	char ch=0;
    	int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
    	return x*flag;
    }
    const int mo=998244353;
    int tot;
    struct node{int x,y;}p[N];
    #define mid ((l+r)>>1)
    #define lb(x) ((+x)&(-x))
    void solve(int l,int r)
    {
    	if(l==r)return;
    	solve(l,mid);
    	solve(mid+1,r);
    	for(int i=l,j=mid+1;i<=mid&&j<=r;i++,j++)p[++tot]={i,j};
    }
    int F(int x,int y)
    {
    	return ((x^y^(x+y))+(x+y)+(x/y)+(y/x))%mo;
    }
    int a[N],f[N],g[N],nw[N];
    int main()
    {
    	int n=read(),m=n,cnt=0;
    	while(m)a[++cnt]=lb(m),m-=lb(m);
    	for(int i=1,k=1;i<=cnt;i++)solve(k,k+a[i]-1),k+=a[i];
    	if(cnt<=2)
    	{
    		printf("%d
    ",tot);
    		for(int i=1;i<=tot;i++)printf("%d %d
    ",p[i].x,p[i].y);
    		return 0;
    	}
    	for(int i=1;i<=a[1];i++)nw[i]=i;
    	for(int i=1;i<=n-a[1]-a[cnt];i++)f[i]=a[1]+i;
    	for(int i=1;i<=a[cnt];i++)g[i]=n-a[cnt]+i;
    	
    	for(int i=1,t=0,k=0,len=a[1];i<=cnt-2;i++)
    	{
    		while(len<a[i+1])
    		{
    			int tmp=len;
    			for(int j=1;j<=tmp;j++)p[++tot]={nw[j],g[++t]},nw[++len]=g[t];
    		}
    		int tmp=len;
    		for(int j=1;j<=tmp;j++)p[++tot]={nw[j],f[++k]},nw[++len]=f[k];
    	}
    	printf("%d
    ",tot);
    	for(int i=1;i<=tot;i++)printf("%d %d
    ",p[i].x,p[i].y);
    	/*
    	for(int i=1;i<=n;i++)a[i]=i;
    	for(int i=1;i<=tot;i++)
    	{
    		int x=p[i].x,y=p[i].y;
    		a[x]=a[y]=F(a[x],a[y]);
    	}
    	for(int i=1;i<=n;i++)cout<<a[i]<<endl;
    	*/
    	return 0;
    }
    
  • 相关阅读:
    C++ linux 共享内存的学习
    C++11 result_of 学习
    C++线程池 基于Cpp98的实现 学习2 未完待续
    Piecewise Smooth Subdivision Surfaces with Normal Control 未完待续
    C++线程池 基于C的实现 学习1
    C++ 标准函数 。abort & typeid
    线段树(区间更新, 区间查询 ,线段染色)
    bfs(标记整个棋盘)
    stringstream流分割空格
    lcm与gcd
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/13853725.html
Copyright © 2011-2022 走看看