有N (1 ≤ N ≤ 5,000) 头牛,每头牛要么面朝前方(F)要么面朝后方(B)。现在可以连续驱使连续的K头牛反转。求使得所有的牛面朝前方的最小操作数(M), 和对应的K各是多少?
Input
Line 1: A single integer: N
Lines 2… N+1: Line i+1 contains a single character, F or B, indicating whether cow i is facing forward or backward.
Output
输出每次反转K头奶牛面向前方所需的最小机器操作次数M。
Sample Input
7
B
B
F
B
F
B
B
Sample Output
3 3
Hint
For K = 3, the machine must be operated three times: turn cows (1,2,3), (3,4,5), and finally (5,6,7)
解题报告:
这道题如果枚举每个开关,复杂度1<<n肯定不行,因为要求的是最小的翻转次数,那么我们枚举k(连续的反转区间长度)是不可避免的,然后枚举反转的牛的起点,反转每头牛,最坏复杂度n^3,那么优化的话只能来优化最后一维,第i头是否要反转取决于他自身是否头朝后和他的前k-1个牛的翻转次数,那么我们用0来表示朝前,1表示朝后,如果和是奇数那么就是要反转,我们枚举玩前面,看看后面是否存在头朝后面的牛,不行就return -1。
#include<iostream>
#include<cstring>
using namespace std;
const int N=5010;
int dir[N];
int f[N];
int n;
int solve(int k)
{
memset(f,0,sizeof f);
int sum=0;
int re=0;
for(int i=0;i+k-1<n;i++)
{
if((sum+dir[i])%2)
{
f[i]=1;
re++;
sum+=1;
}
if(i-k+1>=0)
sum-=f[i-k+1];
}
for(int i=n-k+1;i<n;i++)
{
if((dir[i]+sum)%2) return -1;
// sum+=f[i];
if(i+1-k>=0) sum-=f[i-k+1];
}
return re;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
char s[2];
scanf("%s",s);
if(s[0]=='F')
dir[i]=0;
else
dir[i]=1;
}
int ans=1e9;
int ansk;
for(int k=1;k<=n;k++)
{
int cnt=solve(k);
if(cnt<ans&&cnt!=-1)
{
ans=cnt;
ansk=k;
}
}
cout<<ansk<<' '<<ans<<endl;
return 0;
}