Face The Right Way---hdu3276(开关问题)

时间:2021-11-09 16:34:09

题目链接:http://poj.org/problem?id=3276

题意:n牛头排成一排,每头牛两个状态,向前或向后,为了让所有的牛都向前,现在有一个机器 每次 能控制连续K头牛转换自己的状态,求让所有牛都向前的最少操作次数,以及对应的K值;

同一头牛翻转的次数为偶数时,相当于没有翻转;我们可以枚举所有的K,看是否能让所有的牛都面向前,当K一定时,先考虑最左端的牛,如果这头牛已经面向前的,无需翻转,否则翻转,

当左到右的操作之后我们就可以不用考虑左端的情况了;我们用f[i]表示区间[i, i+k-1]的牛是否被翻转;(1翻转,0不翻转);

当看第i头牛的状态时,因为第i头牛是和前面k-1头牛的翻转次数总和有关的,所以如果sum( f[i-k+1] 到 f[i-1] )是否为奇数,说明当前状态与初始状态相反,偶数状态不变;

求和的过程可以优化,所以总的时间复杂度为n*n; 

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<math.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 202550
#define PI 4*atan(1.0)
#define mod 100000001
#define met(a, b) memset(a, b, sizeof(a))
typedef long long LL; int n, dir[N], f[N]; int solve(int k)///判断连续翻转k头牛是否可行;
{
met(f, );///f[i]表示区间i----i+k-1的牛是否翻转; int sum = , cnt = ;///sum表示当前牛被翻转了多少次,等于前k-1个牛的翻转次数和;
for(int i=; i+k-<=n; i++)
{
if((sum+dir[i])%)///如果当前牛的方向是向后;
{
f[i] = ;///翻转i---i+k-1;
cnt ++;
}
sum += f[i];
if(i-k+>)///去除之前的影响;
sum -= f[i-k+];
}
for(int i=n-k+; i<=n; i++)///每次都会剩下不足k个(k-1个)的牛,然后检查这些牛的方向是否向前;
{
if((sum+dir[i])%)///如果当前牛的方向是向后;说明k值不可以,返回-1;
return -;
if(i-k+ > )
sum -= f[i-k+];
}
return cnt;
} int main()
{
while(scanf("%d", &n) != EOF)
{
met(dir, );///0向前,1向后;
for(int i=; i<=n; i++)
{
char s[];
scanf("%s", s);
if(s[] == 'B') dir[i] = ;
}
int K = , Min = n; for(int k=; k<=n; k++)
{
int ans = solve(k);
if(ans == -) continue;
if(ans < Min)
{
Min = ans;
K = k;
}
}
printf("%d %d\n", K, Min);
}
return ;
}