http://poj.org/problem?id=3276
反转两次等于没有反转,反转的次序是无关的。假设所有的格子进行一系列反转操作以后都变成F,那么可以把这一系列操作等价为,按照格子从左到右,每个区间反转1次或者不反转。对于最左边的格子,可以确定到底是反转还是不反转,然后再考虑下一个格子。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<iostream>
#include<algorithm>
#define INF 0x3f3f3f3f
#define N 5005
using namespace std;
int sum, res, n, K, ans, min_ans, f[N], a[N];
int calc(int k)
{
sum = 0;
res = 0;
for (int i = 0; i <= n-k; i++)//f[i]表示[i,i-k+1]是否要反转
{
if ((sum + a[i]) % 2 == 1)
{
f[i] = 1;
res++;
}
sum += f[i];
if (i-k+1 >= 0) sum -= f[i-k+1];//最前面几个格子,不需要减
}
for (int i = n-k+1; i < n; i++)//从第n-k+1个格子开始,就不能够反转了,但是还是要知道通过前面的反转现在它的状态
{
if ((sum + a[i]) % 2 == 1)//第n-k+1个格子还可以用之前遗留下算好的sum,之后就要不断把f[i-k+1]减掉
{
return INF;
}
if (i-k+1 >= 0) sum-= f[i-k+1];
}
return res;
}
int main()
{
scanf("%d", &n);
char s[3];
for (int i = 0; i < n; i++)
{
scanf("%s", s);
if (s[0] == 'B') a[i] = 1;
else a[i] = 0;
}
min_ans = INF;
for (int i = 1; i <= n; i++)
{
memset(f, 0, sizeof(f));
ans = calc(i);
if (ans < min_ans)
{
min_ans = ans;
K = i;
}
}
printf("%d %d\n", K, min_ans);
return 0;
}