zoukankan      html  css  js  c++  java
  • uoj180 【UR #12】实验室外的攻防战

    题目

    我们发现对于排列(A)中,一组(i<j,a_i<a_j),那么我们不可能通过交换把(a_j)换到(a_i)前面

    但是一组(i<j,a_i>a_j),我们却可以通过交换使得(a_j)更靠前,也就是我们在(A)中的交换只能消除一些逆序对,而不能产生新的逆序对

    于是我们想要得到排列(B),必须使得(B)中的任意一个逆序对在(A)中也是逆序的,否则就不可能通过交换使得(A)变成(B);即一旦(B)中一个逆序对在(A)中是顺序的,我们就输出(NO)

    之后就开始智商下降了,强行莫队+值域分块

    我们对于一个数(i),我们设其在(A)中的出现位置为(posa_i),在(B)中出现的位置为(posb_i),那么我们就把((posa_i,posb_i))视为一个点对,将(A)序列中的([1,posa_i])的数都加入值域块,点权为(1)([1,posb_i])的数也都加入值域块,点权为(-1),如果这个时候有一个大于(i)的点点权为(-1),那么就说明这个点在(B)中和(i)形成了逆序对,但是在(A)中却没有。所有点的加入可以通过莫队保证复杂度。

    复杂度是(O(nsqrt{n})),成功位列uoj倒数第五

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int maxn=1e5+5;
    struct Point{int x,y,rk;}p[maxn];
    int a[maxn],b[maxn],id[maxn],B,n,cnt,L[500],R[500];
    int tax[maxn],tag[500];
    inline void add(int x,int v) {
    	tax[x]+=v;
    	if(v==1&&tax[x]==0) tag[id[x]]--;
    	if(v==-1&&tax[x]==-1) tag[id[x]]++;
    }
    inline int find() {
    	for(re int i=cnt;i;--i) {
    		if(!tag[i]) continue;
    		for(re int j=R[i];j>=L[i];--j) 
    			if(tax[j]==-1) return j;
    	} 
    	return 0;
    }
    inline int cmp(Point A,Point B) {return id[A.x]==id[B.x]?A.y<B.y:A.x<B.x;}
    int main() {
    	n=read();B=std::sqrt(std::ceil(n));
    	for(re int i=1;i<=n;i++) p[i].rk=i;
    	for(re int i=1;i<=n;i++) a[i]=read(),p[a[i]].x=i;
    	for(re int i=1;i<=n;i++) b[i]=read(),p[b[i]].y=i;
    	for(re int l=1,r;l<=n;l=r+1) {
    		r=min(n,l+B-1);++cnt;L[cnt]=l,R[cnt]=r;
    		for(re int j=l;j<=r;++j) id[j]=cnt;
    	}
    	std::sort(p+1,p+n+1,cmp);
    	int l=0,r=0;
    	for(re int i=1;i<=n;i++) {
    		while(l<p[i].x) add(a[++l],1);
    		while(l>p[i].x) add(a[l--],-1);
    		while(r<p[i].y) add(b[++r],-1);
    		while(r>p[i].y) add(b[r--],1);
    		if(find()>p[i].rk) return puts("NO"),0;
    	}
    	puts("YES");
    	return 0;
    }
    

    正解其实非常简单,我们维护一个树状数组,按照(i)从小到大把((posa_i,posb_i))插入树状数组;插入之前查一下之前插入的(j)中满足(posa_j<posa_i)(posb_j)的最大值,如果这个最大值大于(posb_i),那么就说明了(A)中的一个顺序对在(B)中变成了逆序对,直接输出(NO)即可。

  • 相关阅读:
    Asp.net 中 OnClientClick 与 OnClick 的区别
    WPF + RDLC + Tablix动态生成列 + 表头合并
    统计表用于查询效果太差的情况
    TeamView WaitforConnectFailed错误原因
    瞄到BindingGroup用法
    最讨厌工作时候百度的信息
    Lambda获取类属性的名字
    附加属性作用于多选控件,用于获取所有选中项
    文件夹图标错落解决方案
    WPF Line 的颜色过度动画
  • 原文地址:https://www.cnblogs.com/asuldb/p/11572095.html
Copyright © 2011-2022 走看看