Face The Right Way 开关(POJ3276)

描述:
\( N 头牛排成了一列。每头牛或者向前或者向后。为了让所有的牛都面向前方,农夫约翰买了 一台自动转向的机器。 这个机器在购买时就必须设定一个数值 K,机器每操作一次恰好使 K 头连续的牛转向。 请求出为了让所有的牛都能面向前方需要的最少的操作次数 M 和对应的 最小的 K。 前是'F',后是'B'\)

枚举一个K,然后考虑如何求出此时的M.

一、如果第一头牛需要反转,因为只有1-K这个区间包含它,所以一定要翻转

二、考虑第二头牛,如果需要翻转那么重复上面的步骤。

这样的复杂度是\(O(n^3)\)

每次翻转牛,需要把k头牛都去翻转,这太麻烦了,可以优化掉。

\(f[i]\)表示以i为起点的区间是否翻转过

那么如果f[i]=1,它的效果一直持续到f[i+k]就失效了

所以维护一个sumn变量,表示在i以前k-1头牛翻转过的次数

那么每次循环,要sumn-=f[i-k+1],因为已经失效

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n,f[5009];//f[i]表示i,i+1,.....i+k-1牛都反转
char cow[5009];
int fun(int k)
{
	memset(f,0,sizeof(f));
	int ans=0;//反转次数
	int sumn=0;
	for(int i=1;i<=n-k+1;i++)
	{
		if(sumn%2==0&&cow[i]=='B')//要反转了 
			f[i]=1,ans++;
		else if(sumn%2==1&&cow[i]=='F')//要反转了
			f[i]=1,ans++;
		sumn+=f[i];
		if(i-k+1>=1)	sumn-=f[i-k+1];
	} 
	//第n-k+2头牛以后不能反转了,判断是否可行
	for(int i=n-k+2;i<=n;i++)
	{
		if(sumn%2==0&&cow[i]=='B')	return -1;
		else if(sumn%2==1&&cow[i]=='F')	return -1;
		sumn+=f[i];
		if(i-k+1>=1)	sumn-=f[i-k+1];
	}
	return ans; 
} 
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>cow[i];
	int k,ans=999999999;
	for(int i=1;i<=n;i++)//判断步长i时是否可行 
	{
		int x=fun(i);
		if(x!=-1&&x<ans)
		k=i,ans=x;
	}
	cout<<k<<" "<<ans;
}
posted @ 2020-03-31 15:42  倾叶子佮  阅读(137)  评论(0)    收藏  举报