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

题目链接: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, 0);///f[i]表示区间i----i+k-1的牛是否翻转;

    int sum = 0, cnt = 0;///sum表示当前牛被翻转了多少次,等于前k-1个牛的翻转次数和;
    for(int i=1; i+k-1<=n; i++)
    {
        if((sum+dir[i])%2)///如果当前牛的方向是向后;
        {
            f[i] = 1;///翻转i---i+k-1;
            cnt ++;
        }
        sum += f[i];
        if(i-k+1>0)///去除之前的影响;
            sum -= f[i-k+1];
    }
    for(int i=n-k+2; i<=n; i++)///每次都会剩下不足k个(k-1个)的牛,然后检查这些牛的方向是否向前;
    {
        if((sum+dir[i])%2)///如果当前牛的方向是向后;说明k值不可以,返回-1;
            return -1;
        if(i-k+1 > 0)
            sum -= f[i-k+1];
    }
    return cnt;
}

int main()
{
    while(scanf("%d", &n) != EOF)
    {
        met(dir, 0);///0向前,1向后;
        for(int i=1; i<=n; i++)
        {
            char s[10];
            scanf("%s", s);
            if(s[0] == 'B') dir[i] = 1;
        }
        int K = 1, Min = n;

        for(int k=1; k<=n; k++)
        {
            int ans = solve(k);
            if(ans == -1) continue;
            if(ans < Min)
            {
                Min = ans;
                K = k;
            }
        }
        printf("%d %d\n", K, Min);
    }
    return 0;
}
View Code

 

posted @ 2016-08-20 17:26  西瓜不懂柠檬的酸  Views(134)  Comments(0Edit  收藏  举报
levels of contents