• 【CF578E】Walking!(贪心)


    点此看题面

    • 给定一个长度为(n)的由LR构成的字符串(s)
    • 求构造一个排列(p_i),满足(forall iin[1,n),s[p_i] ot=s[p_{i+1}]),且满足(p_i>p_{i+1})(i)的个数最小。
    • (nle10^5)

    可以证伪的贪心

    考虑一个贪心,就是每次尽可能选取长度最大的符合条件的子序列,然后重复取若干次直至把整个序列取完。

    这一过程的实现是非常简单的,只要对LR两种字符各开一个(set),每次(lower\_bound)找后继就好了。

    然而,这个贪心是会被卡掉的。

    唯一一种(Hack)数据

    会被卡掉是毋庸置疑的,但能卡掉这个贪心的数据实际上只有一种。

    L为例,如果它选中的R后面全都是R,且在此之前还有R没有匹配,这时候贪心就会有问题。

    因为根据贪心的思路我们会先匹配后面的R再折回去找之前的LR,那么不如先回去匹配前面的R再一路匹配下来。

    只要特判一下这种情况就可以了。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    using namespace std;
    int n,v[N+5];char s[N+5];set<int> S[2];
    I int Solve(RI x)//第一个字符为x
    {
    	RI i,t=0;for(i=1;i<=n;++i) S[s[i]=='R'].insert(i);//分字符插入set
    	#define Nxt(x,p) S[x].lower_bound(p)//后继
    	#define Mn(x) *S[x].begin()//最小值
    	RI p=0;for(i=1;i<=n;S[x].erase(v[i]=p),++i,x^=1)
    		p=Nxt(x,p)==S[x].end()?(++t,Mn(x)):*Nxt(x,p),//找到下一位
    		Nxt(x^1,p)==S[x^1].end()&&p^Mn(x)&&Mn(x)<Mn(x^1)&&(p=Mn(x),++t);//如果之后全是同样的字符,不如先选前面的
    	return t;
    }
    int main()
    {
    	RI i,t=0;for(scanf("%s",s+1),n=strlen(s+1),i=1;i<=n;++i) s[i]=='L'?++t:--t;//比较两种字符谁更多
    	for(printf("%d
    ",t?Solve(t==-1):Solve(s[1]=='R')),i=1;i<=n;++i) printf("%d ",v[i]);return 0;
    }
    
  • 相关阅读:
    html优化
    HTML练习(网页计算器)
    hdu--4574 Bombs(dfs)
    Robots at Warehouse(搜索+vector的使用)
    poj 2111 Millenium Leapcow(记忆化搜索)
    Codeforces Round #408 (Div. 2) C. Bank Hacking(暴力啊!暴力)
    Gym
    Gym
    浙江省赛--D
    浙江省赛--C
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF578E.html
Copyright © 2020-2023  润新知