1. 程式人生 > >B(2187): 翻轉游戲加強版

B(2187): 翻轉游戲加強版

B(2187): 翻轉游戲加強版

Submit Page    Summary    Time Limit: 1 Sec     Memory Limit: 128 Mb     Submitted: 39     Solved: 8    


Description

給當一個01串,最多可以對一段區間裡的01取反一次,求最多能取得的1的個數

Input

多組資料,第一行為陣列組數T(T<=10)

每組資料第一行一個整數N,1<=N<=1000000

第二行一個長度為N的01字串

Output

每組資料輸出一行代表答案

Sample Input

2
4
1001
4
1111

Sample Output

4
4

解法:

設f[x]為01串下標1到x中1的個數(我的下標從1開始),d[x]為01串下標1到x中0的個數,假設我翻轉了 l r區間,那麼ans=f[n]-f[r]+f[l-1]+d[r]-d[l-1],f[n]是常數,我們變形一下,答案值和這個有關:f[l-1]-d[l-1]-(f[r]-d[r]),那麼只要這個式子最大,答案才最大,我們令h[x]=f[x]-d[x],只要找到兩個數 l r(l<=r),使得h[l]-h[r]最大即可。
--------------------- 
作者:一隻叫橘子的貓 
來源:CSDN 
原文:https://blog.csdn.net/ccsu_cat/article/details/83933795 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

下面的註釋是我對這個的解法的理解。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
char s[maxn];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d%s",&n,s+1);
		int p0=0,p1=0,mx=0,t=0,p=0,ans=0;;
		for(int i=1;i<=n;i++)
		{
			ans+=s[i]-'0';
			if(s[i]=='0') p0++;
			else p1++;
			t=p1-p0;
			/*
			最重要的兩句就是這兩句
			數學推論題 
			*/
			p=max(p,mx-t);
			/*
			p就是答案最大的h(l)-h(r)
			mx就是儲存最大的h(l)
			t就是列舉h(r) 
			t=p1-p0即f(x)-d(x)
			比較妙的一種數學題吧 
			*/ 
			mx=max(t,mx);
		}
		printf("%d\n",ans+p);
	}
}