• CF1558F Strange Sort


    一、题目

    点此看题

    二、解法

    ( t oneindark) 真的离谱,这种题都能切呢?(3300) 的题都能切呢?!

    首先我们应用 (01) 原则,(forall i),我们把前 (i) 小的数变成 (0),剩下的数变成 (1),然后对这个数列排序,所有排序次数取最大值就是答案。每次得到的条件是前 (i) 小的数被排好序了,所以大家都被排好序了。

    结论:(01) 序列的排序次数为某个在 (0) 前面的 (1),其前面 (1) 的个数(+)后面 (0) 的个数(+[)这是否是偶数位置(])的最大值。

    考虑 (f(i,j)) 表示第 (i)(1) 越过第 (j)(0) 的排序次数,转移:

    [f(i,j)=max(f(i+1,j),f(i,j-1))+1 ]

    这其实相当于图上求最长链,那么我们考虑每个叶子的最长链即可,每次可以向左使 (i-1),向右使 (j+1),初值和位置 (i) 的奇偶性有关,然后加上前面 (1) 的个数和后面 (0) 的个数即可。

    因为这个函数定义在 (1) 上所以只能在 (1) 位置取最值,因为只有在 (0) 前面的 (1) 有定义所以只能考虑它。

    用线段树把上面的结论模拟出来即可,时间复杂度 (O(nlog n))

    三、总结

    排序问题可以转 (01) 序列,注意 (01) 原则的应用即可。

    本题反复取 (max) 也是有趣之处,主要思想是把困难的问题拆成若干独立子问题。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int M = 200005;
    const int inf = 0x3f3f3f3f;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,ans,b[M],mx[4*M],fl[4*M];
    void jzm(int i,int c)
    {
    	mx[i]+=c;fl[i]+=c;
    }
    void down(int i)
    {
    	jzm(i<<1,fl[i]);
    	jzm(i<<1|1,fl[i]);
    	fl[i]=0;
    }
    void build(int i,int l,int r)
    {
    	mx[i]=fl[i]=0;
    	if(l==r)
    	{
    		mx[i]=-inf+(l%2==0)+l-1;
    		return ;
    	}
    	int mid=(l+r)>>1;
    	build(i<<1,l,mid);
    	build(i<<1|1,mid+1,r);
    	mx[i]=max(mx[i<<1],mx[i<<1|1]);
    }
    void add(int i,int l,int r,int L,int R,int c)
    {
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R) {jzm(i,c);return ;}
    	int mid=(l+r)>>1;down(i);
    	add(i<<1,l,mid,L,R,c);
    	add(i<<1|1,mid+1,r,L,R,c);
    	mx[i]=max(mx[i<<1],mx[i<<1|1]);
    }
    signed main()
    {
    	T=read();
    	while(T--)
    	{
    		n=read();ans=0;
    		for(int i=1;i<=n;i++)
    			b[read()]=i;
    		build(1,1,n);
    		for(int i=1,j=1;i<=n;i++)//1->0
    		{
    			int x=b[i];
    			for(;j<=x;j++) add(1,1,n,j,j,inf);
    			add(1,1,n,x,x,-inf);
    			add(1,1,n,x,n,-1);
    			add(1,1,n,1,x-1,1);
    			ans=max(ans,mx[1]);
    		}
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    多线程中,上锁的理解
    sql server 2008 联机丛书
    序列化是线程安全的么
    对象化下的编程——字段
    Dic实现工厂模式
    design principle:java 回调与委派/委托机制(转)
    风筝数据结构学习笔记(2)后序遍历二叉树(非递归)
    风筝数据结构学习笔记(1)利用链式存储结构和递归构建二叉树
    吕震宇老师《设计模式系列》
    吕震宇老师《设计模式随笔系列》
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15221114.html
Copyright © 2020-2023  润新知