zoukankan      html  css  js  c++  java
  • Codeforces 578E. Walking!(贪心+线段树)

    Codeforces 578E. Walking!

    题目大意

    • 给出一个长度为 N N N字符串 S S S,由’L’和‘R’组成,
    • 求一个 N N N的排列 P P P,使得 S P i ≠ S p i + 1 S_{P_i}≠S_{p_{i+1}} SPi=Spi+1,也就是说要满足选择的相邻两个都不相同,
    • 同时要最小化 p i > p i + 1 p_i>p_{i+1} pi>pi+1的个数,也就是使排列相邻的两个数前一个大于后一个的数量最少。
    • 数据保证有解。
    • N ≤ 1 ∗ 1 0 5 N≤1*10^5 N1105

    题解

    • 观察样例再自己手玩一下,很快就发现可以贪心,
    • 首先显然若’R’的数量多,则第一个从’R’开始,反之同理;若两种字符一样多,则从哪个开始都可以。
    • 先尽量选择左边的,然后向右继续选最靠近它的符合条件的,这样一直下去,直到最后面选不了了,再回到最左边一个符合条件的,以此类推不断往复,似乎就可以求出最小答案,而且特别显然,可以用线段树维护。
    • 但是发现有一种特殊情况,
    • 假如出现“RLLR”的情况,且当前在第二个’L’的位置,按照贪心我们会先向右找一个’R’,然后发现没有了,返回左边第一个’L’,然后它后面也没有‘R’了,又往左一次返回到第一个’R’,这样返回了两次,
    • 而如果先直接返回第一个’R’,接下来就可以一直顺着走完,那么只返回了一次,更优。
    • 所以需要判断一下,如果当前字符为’L’,它右边的第一个‘R’右边剩下的全是‘R’,且从左边起第一个剩下的也是‘R’,那么直接回到最左边的‘R’;如果当前为‘R’同理。
    • 这样答案是正确的。

    代码

    #include<cstdio> 
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 100010
    char st[N];
    int a[N], n;
    int f[2][N * 4], ans[2][N], bz[N], fa[N], s[2], nxt[N];
    void ins(int v, int l, int r, int x, int o, int c) {
    	if(l == r) f[o][v] = c;
    	else {
    		int mid = (l + r) / 2;
    		if(x <= mid) ins(v * 2, l, mid, x, o, c);
    		else ins(v * 2 + 1, mid + 1, r, x, o, c);
    		f[o][v] = min(f[o][v * 2], f[o][v * 2 + 1]);
    	}
    }
    int find(int v, int l, int r, int x, int y, int o) {
    	if(l == x && r == y) return f[o][v];
    	int mid = (l + r) / 2;
    	if(y <= mid) return find(v * 2, l, mid, x, y, o);
    	if(x > mid) return find(v * 2 + 1, mid + 1, r, x, y, o);
    	return min(find(v * 2, l, mid, x, mid, o), find(v * 2 + 1, mid + 1, r, mid + 1, y, o));
    }
    int get(int k) {
    	if(fa[k] == k) return k;
    	return fa[k] = get(fa[k]);
    }
    int ss = 0;
    int ct(int l, int o) {
    	if(l >= n) return n + 1;
    	int l1 = find(1, 1, n, l + 1, n, o);ss++;
    	while(bz[l1]) {
    		if(l1 == n) return n + 1;
    		int l2 = nxt[l1];
    		fa[l1] = get(l2);
    		l1 = fa[l2];
    	}
    	return l1;
    }
    void solve(int o) {
    	int i;
    	s[0] = s[1] = n + 1;
    	memset(bz, 0, sizeof(bz));
    	for(i = n; i; i--) {
    		nxt[i] = s[a[i]];
    		fa[i] = i;
    		s[a[i]] = i;
    		ins(1, 1, n, i, 0, s[0]);
    		ins(1, 1, n, i, 1, s[1]);
    	} 
    	fa[n + 1] = n + 1;
    	int l = 0, r = o; ans[o][0] = 0;
    	for(i = 1; i <= n; i++)	{
    		int tt = ct(0, r);
    		if(ct(ct(l, r), 1 - r) == n + 1 && tt < ct(0, 1 - r)) {
    			int l1 = tt;
    			if(l1 < l) ans[o][0]++;
    			l = ans[o][i] = l1;
    			bz[l] = 1;
    			r = 1 - r;
    			continue;
    		}
    		
    		int l1 = ct(l, r);
    		if(l1 == n + 1) {
    			ans[o][0]++;
    			l1 = ct(0, r);
    		}
    		l = ans[o][i] = l1;
    		bz[l] = 1;
    		r = 1 - r;
    	}
    }
    int main() {
    	scanf("%s", st + 1);
    	n = strlen(st + 1);
    	int t[2] = {0, 0}, i;
    	for(i = n; i; i--) {
    		a[i] = (st[i] == 'R');
    		t[a[i]]++;
    	}
    	ans[0][0] = ans[1][0] = n + 1;
    	if(t[1] >= t[0]) solve(1);
    	if(t[0] >= t[1]) solve(0);
    	int o;
    	if(ans[0][0] < ans[1][0]) o = 0; else o = 1;
    	printf("%d
    ", ans[o][0]);
    	for(i = 1; i <= n; i++) printf("%d ", ans[o][i]);
    	return 0;
    } 
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    Running ASP.NET Applications in Debian and Ubuntu using XSP and Mono
    .net extjs 封装
    ext direct spring
    install ubuntu tweak on ubuntu lts 10.04,this software is created by zhouding
    redis cookbook
    aptana eclipse plugin install on sts
    ubuntu open folderpath on terminal
    ubuntu install pae for the 32bit system 4g limited issue
    EXT Designer 正式版延长使用脚本
    用 Vagrant 快速建立開發環境
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910029.html
Copyright © 2011-2022 走看看