首页 > 代码库 > codeforces Flipping Game 题解

codeforces Flipping Game 题解

Iahub got bored, so he invented a game to be played on paper.

He writes n integers a1,?a2,?...,?an. Each of those integers can be either 0 or 1. He‘s allowed to do exactly one move: he chooses two indices i and j (1?≤?i?≤?j?≤?n) and flips all values ak for which their positions are in range[i,?j] (that is i?≤?k?≤?j). Flip the value of x means to apply operation x?=?1 - x.

The goal of the game is that after exactly one move to obtain the maximum number of ones. Write a program to solve the little game of Iahub.

Input

The first line of the input contains an integer n (1?≤?n?≤?100). In the second line of the input there are n integers:a1,?a2,?...,?an. It is guaranteed that each of those n values is either 0 or 1.

Output

Print an integer — the maximal number of 1s that can be obtained after exactly one move.

Sample test(s)
input
5
1 0 0 1 0
output
4
本题因为数据量小,可以使用暴力法,时间效率是O(n^3)

但是这里巧用最大子段和的思想,可以把时间效率降到O(n)

思想:

1 想使用一个新的数列,计算连续出现了多少个1和连续出现了多少个零

2 求这个新数列的最大子段和

3 Flip最大子段中的 0 和 1,

4 计算出结果

比暴力法复杂很多了,但是时间效率却提高了三个档次。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

void FlippingGame()
{
	int n, a;
	cin>>n;
	vector<bool> vbn(n);
	for (int i = 0; i < n; i++)
	{
		cin>>a;
		vbn[i] = a;
	}
	vector<int> ans;
	int c = 1;
	for (int i = 1; i < n; i++)
	{
		if (vbn[i] == vbn[i-1]) c++;
		else
		{
			if (vbn[i-1]) ans.push_back(-c);
			else ans.push_back(c);
			c = 1;
		}
	}
	if (vbn.back()) ans.push_back(-c);
	else ans.push_back(c);

	//求最大子段和思想
	int stTmp = 0, st = ans.size(), end = ans.size(), maxVal = 0, sum = 0;
	for (unsigned i = 0; i < ans.size(); i++)
	{
		sum += ans[i];
		if (sum > maxVal)
		{
			st = stTmp;
			maxVal = sum;
			end = i;
		}
		if (sum <= 0) 
		{
			sum = 0;
			stTmp = i+1;
		}
	}

	int nums = 0;
	for (int i = 0; i < ans.size(); i++)
	{
		if (ans[i] < 0) nums += ans[i];
	}
	if (maxVal > 0) cout<<maxVal - nums;
	else cout<<-(ans.front()+1);
}