http://poj.org/problem?id=3276
题意:N头牛排成一列1<=N<=5000。每头牛或者向前或者向后。为了让所有牛都面向前方,农夫每次可以将K头连续的牛转向1<=K<=N,求操作的最少次数M和对应的最小K。
由于交换区间翻转顺序对结果没影响,所以从左往右对于需要翻转的牛进行反转,同时记录对该区间其他牛的影响即cal中的sum,对于最后部分无法翻转的区间检查是否有反向牛,若有则方案失败。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
char ch;
int N;
int d[5005]; //方向
int f[5005]; //是否转第i头牛
//固定K,求对应的最小操作数
//无解返回-1
int calc(int K){
memset(f,0,sizeof(f));
int ans=0; //转的次数
int sum=0; //f的和
for(int i=0;i+K-1<N;i++){
if ((d[i]+sum)&1){ //前端的牛面朝后方
ans++;
f[i]=1;
}
sum+=f[i]; //尺取法
if (i-K+1>=0){
sum-=f[i-K+1];
}
}
//检查剩下的是否有反向奶牛
for (int i=N-K+1;i<N;i++){
if ((d[i]+sum)&1){
return -1;
}
if (i-K+1>=0){
sum-=f[i-K+1];
}
}
return ans;
}
int main(){
cin >> N;
for (int i=0;i<N;i++){
cin >> ch;
if (ch=='B'){
d[i]=1;
}
else{
d[i]=0;
}
}
int K=1,M=N;
for (int k=1;k<=N;k++){
int m=calc(k);
if (m>=0&&M>m){
M=m;
K=k;
}
}
cout << K << " " << M << endl;
}