题目链接:
http://poj.org/submit?problem_id=3276http://poj.org/submit?problem_id=3276
题目大意:
N头牛站成一排,每头牛要么向前要么向后(F表示向前,B表示向后),为了让所有的牛都面向前方,约翰买了一台自动旋转的机器,每次旋转设定一个固定的k值,机器操作一次就旋转连续的k头牛,求出为了让所有牛都面向前方的的最少操作次数m和对应的k值。
思路:
在k确定的情况下,可以只看区间中第一头牛是否需要反转(因为这头牛只能在当前反转,后面的反转不会影响到它),以此确定是否反转,这样就能确定唯一解了。遍历前n-k+1头牛之后,再看剩下的牛是否都是正确方向,如果是,说明当前k能满足题意,否则不能。
所以要对所有的k都求解一次,取对应的m最小值。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string.h>
#include <climits>
using namespace std;
const int MAXN = 5005;
// 题目要求计算最小的M和对应最小的K
int N, K, M; // 牛数量,反转长度,反转次数
int dir[MAXN]; // 原本的方向
int tra[MAXN]; // 表示[i, i+K-1]部分的牛反转
// 固定K,返回最小的操作次数M, 无解的话返回-1
int calc(int K){
memset(tra, 0, sizeof(tra)); // 重置reverse数组
int res = 0, count = 0; // 总反转次数,当前牛的反转次数
for(int i=0; i<=N-K; i++){ // 遍历所有可反转位置的头部牛
if ((dir[i] + count) % 2 != 0) { // 表示需要反转
res++;
tra[i] = 1;
}
// 更新当前窗口内的count值(为下一次做准备)
count += tra[i];
if(i-K+1 >= 0) count -= tra[i-K+1];
}
//检查剩下的牛方向是否都正确
for(int i=N-K+1; i<N; i++){
if ((dir[i] + count) % 2 != 0) return -1; //方向不正确,无解
if (i-K+1 >= 0) count -= tra[i-K+1]; //继续维护count的值
}
return res; //符合题意,返回结果
}
int main(){
//快读
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//输入
cin >> N;
for(int i=0; i<N; i++){
char ch; cin >> ch;
if(ch == 'B') dir[i] = 1;
else dir[i] = 0;
}
K = 1, M = N;
for(int k=1; k<=N; k++){
int m = calc(k);
if(m >= 0 && m < M){
//遇到符合题意的更小的m,更新M和对应的k
M = m;
K = k;
}
}
printf("%d %d\n", K, M);
}