题目大意:N头牛排成了一列,但有的朝前有的朝后,现在农夫买了一台机器,但是这台机器购买时必须要设置一个固定的K,每次操作都会使K头连续的牛转向,求出让所有的牛能朝向前的最少次数M和对应的K。
解题思路:显然对同一个区间翻转一次就行了,翻转多次都是多余的。我们需要从最左边的牛开始翻转,因为它只属于一个区间,如果它朝后,那就不得不翻转。所以这个题我们可以去枚举长度k去解决。但是如果我们朴素的求解,枚举每一个k,在枚举区间的起点和翻转区间的k头牛,那这总的复杂度时O(n^3)显然是不行的。区间翻转这里是可以优化的,因为头牛的情况是会收到前k-1的影响的。
s[i]:标记是否被翻转,1就是被翻转,0就是没有被翻转
我们考虑第i头牛时如果 为奇数,那第i头牛就是被翻转了,在结合处状态(1朝后,0朝前)就可以知道这里是否要被翻转但是每一次去计算这样显然不行,并没有优化。但是我们可以知道第i+1头牛时的状态是可以从i得来的。
所以我们用一个sum就可以去更新状态了。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxn 5005
#define inf 0x3f3f3f3f
int n,state[maxn],s[maxn];
//state记录状态,1为朝后,0为朝前 ,s标记是否被翻转
int pd(int k){
memset(s,0,sizeof(s));
int res=0,sum=0,i;
for(i=0;i+k<=n;++i){
if((state[i]+sum)%2!=0){//朝后
res++;
s[i]=1;
}
sum+=s[i];
if(i-k+1>=0){
sum-=s[i-k+1];
}
}
for(i=n-k+1;i<n;++i){//枚举最后不能被翻转的那一段
if((state[i]+sum)%2!=0){
return -1;
}
if(i-k+1>=0){
sum-=s[i-k+1];
}
}
return res;
}
void solve(){
int resm=n,resk=1,i;
for(i=1;i<=n;++i){//枚举k的长度
int tp=pd(i);
if(tp>=0&&tp<resm){
resm=tp;
resk=i;
}
}
printf("%d %d\n",resk,resm);
}
int main(){
int i;
char tp;
scanf("%d",&n);
getchar();
for(i=0; i<n; ++i) {
scanf("%c",&tp);
if(tp=='B')
state[i]=1;
if(tp=='F')
state[i]=0;
getchar();
}
solve();
return 0;
}