zoukankan      html  css  js  c++  java
  • [CSP校内集训]C

    题意

    给一个全排列,小A和小B两人轮流操作,一次操作交换两个数;小B先操作,已知小B每回合交换的数,求最优策略,使得用最少的回合数让排列有序,((nleq 10^5))

    思路

    手搓发现操作顺序没有关系,即AB两人交换操作和B先操作、A再操作无区别(这点分情况讨论很好证);
    答案满足二分性,因为如果(x)时刻排列有序,之后A只需要将B的操作抵消就也是有序的
    二分答案(mid),先进行一遍B的操作,然后再考虑A怎么操作

    将一个无序序列通过交换变成有序序列->一个经典问题(为什么我会想到逆序对啊qwq)

    即将(i)(a_i)连边,显然会形成一些简单环,答案就是n-所有简单环的数量(每个环相互独立,一个环需要(环的大小-1)步还原)

    Code

    #include<bits/stdc++.h>
    #define N 200005
    #define lowbit(x) ((x)&(-(x)))
    #define Min(x,y) ((x)<(y)?(x):(y))
    #define Max(x,y) ((x)>(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    int n,a[N],b[N],c[N],x[N<<1],y[N<<1];
    bool vis[N];
    template <class T>
    void read(T &x)
    {
    	char c; int sign=1;
    	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    bool check(int mid)
    {
    	memset(vis,0,sizeof(vis));
    	memset(c,0,sizeof(c));
    	memcpy(b,a,sizeof(b));
    	//b操作了之后才完成 
    	for(int i=1;i<=mid;++i) swap(b[x[i]],b[y[i]]);
    	int ans=0;
    	for(int i=1;i<=n;++i)
    	{
    		if(!vis[i])
    		{
    			vis[i]=1;
    			int x=b[i];
    			while(!vis[x]) { vis[x]=1; x=b[x]; ++ans; }
    		}
    	}
    	return ans<=mid;
    }
    int main()
    {
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    	read(n);
    	for(int i=1;i<=n;++i) read(a[i]),++a[i];
    	for(int i=1,t=2*n;i<=t;++i) read(x[i]),read(y[i]),++x[i],++y[i];
    	int l=0,r=2*n,ans=0;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid)) ans=mid,r=mid-1;
    		else l=mid+1;
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    2019-08-27-Seo如何做好关键词布局
    layui 表格格式化时间
    js 获取ip
    layui 表格删除多行
    Flask JWT Extended 的令牌和刷新令牌
    解决ubuntu下深度音乐和wine程序托盘图标的问题
    ubuntu 阅读caj文件(cajviewer)
    django 结合 xlwt 实现数据导入excel 并下载
    ubuntu 安装Xournal
    pyQt5 计算器
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11799737.html
Copyright © 2011-2022 走看看