3540: [Usaco2014 Open]Fair Photography

3540: [Usaco2014 Open]Fair Photography

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 243   Solved: 113
[ Submit][ Status][ Discuss]

Description

FJ's N cows (2 <= N <= 100,000) are standing at various positions along a long one-dimensional fence. The ith cow is standing at position x_i (an integer in the range 0...1,000,000,000) and is either a plain white cow or a spotted cow. No two cows occupy the same position, and there is at least one white cow. FJ wants to take a photo of a contiguous interval of cows for the county fair, but in fairness to his different cows, he wants to ensure there are equal numbers of white and spotted cows in the photo. FJ wants to determine the maximum size of such a fair photo, where the size of a photo is the difference between the maximum and minimum positions of the cows in the photo. To give himself an even better chance of taking a larger photo, FJ has with him a bucket of paint that he can use to paint spots on an arbitrary subset of his white cows of his choosing, effectively turning them into spotted cows. Please determine the largest size of a fair photo FJ can take, given that FJ has the option of painting some of his white cows (of course, he does not need to paint any of the white cows if he decides this is better).

可以先任意把0染成1.

区间长度定义为,[L,R]中最右和最左的数的差的绝对值.

求一个最长区间,满足区间中所有数0和1的个数相同.

Input

 * Line 1: The integer N.

* Lines 2..1+N: Line i+1 contains x_i and either W (for a white cow) or S (for a spotted cow). 

Output

* Line 1: The maximum size of a fair photo FJ can take, after possibly painting some of his white cows to make them spotted.

Sample Input

5
8 W
11 S
3 W
10 W
5 S

INPUT DETAILS: There are 5 cows. One of them is a white cow at position 8, and so on.

Sample Output

7
OUTPUT DETAILS: FJ takes a photo of the cows from positions 3 to positions 10.
There are 4 cows in this range -- 3 white and 1 spotted -- so he needs to paint one
of the white cows to make it spotted.

HINT

Source

[ Submit][ Status][ Discuss]




把白色奶牛看成-1,斑点奶牛看成1

题目转变成,选择一段最长的包含偶数头奶牛的区间,里面的白牛数目大于等于斑点牛数

将奶牛按照坐标升序排序,想到分治

那么我们只需要处理跨过中间两头奶牛的区间就行了

很显然的想法是,,

对于所有[i,mid],处理出后缀和为k的最长选择

对于所有[mid+1,i]处理出后缀和为k的最长选择

这个k可能为负数,,多开一个数组而已

但是题目还能染色。。。。这就有点啰嗦了

把某头白牛染成黑牛,那么它所在的区间权值+2,

先考虑左半段的处理,,,对于某个区间[i,mid],假设有a头斑点牛和b头白牛

那么这个区间的权值累计能是[a-b,a+b]中某个数,,能取到的数两两相差1

再往左选两头奶牛

两白[a - b - 2.a + b + 2] 相差为2
两黑[a + 2 - b,a + b + 2] 相差为2
一黑一白[a - b,a + b + 2] 相差为2

可以发现会更新的区间是在增大的

而且,,如果你只取一头的话,,下次更新的区间和当前更新区间毫无关联

那么分奇偶,倒着更新即可。。。。。。。。。。代码有点长,不过很大部分是通过copy然后修改的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn = 1E5 + 10;
const int INF = ~0U>>1;

struct Cow{
	int pos,typ; Cow(){}
	Cow(int pos,int typ): pos(pos),typ(typ){}
	bool operator < (const Cow&b) const {return pos < b.pos;}
}cow[maxn];

int n,ans,la[maxn],lb[maxn],ra[maxn],rb[maxn];

void Work(int x,int y,int *A,int *B,int delta)
{
	for (int i = x; i <= y; i += 2) 
		if (i >= 0) A[i] = delta;
		else B[-i] = delta;
}

void Build1(int L,int R,int *A,int *B)
{
	int a = 0,b = 0,l[2],r[2],cur = 0,nex = 1;
	for (int i = R; i >= L; i--) 
		if (cow[i].typ == 1) ++a; else ++b;
	l[0] = a - b; r[0] = a + b;
	Work(l[0],r[0],A,B,cow[R].pos - cow[L].pos);
	if (cow[L].typ == 1) --a; else --b;
	l[1] = a - b; r[1] = a + b;
	if (L != R) Work(l[1],r[1],A,B,cow[R].pos - cow[L+1].pos);
	if (cow[L+1].typ == 1) --a; else --b;
	for (int i = L + 2; i <= R; i++,swap(cur,nex)) {
		int nl = a - b,nr = a + b;
		if (nl < l[cur]) {
			Work(nl,l[cur] - 2,A,B,cow[R].pos - cow[i].pos);
			l[cur] = nl;
		}
		if (nr > r[cur]) {
			Work(r[cur] + 2,nr,A,B,cow[R].pos - cow[i].pos);
			r[cur] = nr;
		}
		if (cow[i].typ == 1) --a; else --b;
	}
}

void Build2(int L,int R,int *A,int *B)
{
	int a = 0,b = 0,l[2],r[2],cur = 0,nex = 1;
	for (int i = L; i <= R; i++) 
		if (cow[i].typ == 1) ++a; else ++b;
	l[0] = a - b; r[0] = a + b;
	Work(l[0],r[0],A,B,cow[R].pos - cow[L].pos);
	if (cow[R].typ == 1) --a; else --b;
	l[1] = a - b; r[1] = a + b;
	if (L != R) Work(l[1],r[1],A,B,cow[R-1].pos - cow[L].pos);
	if (cow[R-1].typ == 1) --a; else --b;
	for (int i = R - 2; i >= L; i--,swap(cur,nex)) {
		int nl = a - b,nr = a + b;
		if (nl < l[cur]) {
			Work(nl,l[cur] - 2,A,B,cow[i].pos - cow[L].pos);
			l[cur] = nl;
		}
		if (nr > r[cur]) {
			Work(r[cur] + 2,nr,A,B,cow[i].pos - cow[L].pos);
			r[cur] = nr;
		}
		if (cow[i].typ == 1) --a; else --b;
	}
}

void Solve(int L,int R)
{
	if (L == R) return;
	int mid = (L + R) >> 1;
	Solve(L,mid); Solve(mid + 1,R);
	int len = max(mid - L + 1,R - mid);
	for (int i = 0; i <= len; i++) 
		la[i] = lb[i] = ra[i] = rb[i] = -1;
	Build1(L,mid,la,lb); Build2(mid + 1,R,ra,rb);
	int now = -INF;
	if (la[0] != -1) now = max(now,la[0]);
	if (lb[0] != -1) now = max(now,lb[0]);
	if (la[0] != -1 && ra[0] != -1) now = max(now,la[0] + ra[0]);
	for (int i = 1; i <= len; i++) {
		if (ra[i] != -1 && lb[i] != -1) 
			now = max(now,ra[i] + lb[i]);
		if (rb[i] != -1 && la[i] != -1) 
			now = max(now,rb[i] + la[i]);
	}
	ans = max(ans,now + cow[mid+1].pos - cow[mid].pos);
}
 
int getint()
{
	char ch = getchar();
	int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}
 
int gettyp()
{
	char ch = getchar();
	while (ch != 'W' && ch != 'S') ch = getchar();
	return ch == 'W'?-1:1;
}
 
int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	n = getint();
	for (int i = 1; i <= n; i++) {
		int pos = getint();
		int typ = gettyp();
		cow[i] = Cow(pos,typ);
	}
	sort(cow + 1,cow + n + 1);
	Solve(1,n);
	cout << ans;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值