poj 3276 Face The Right Way 反转(开关问题)

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

 

枚举每次转向的牛数K 是O(n)

每次转向调整后面牛的状态O(n)

从头到尾转O(n)

总共O(n^3)

 

注意到第二个循环有一些冗余

拿这个来优化

用一个sum来记录区间(i - K ~ i - 1)转向了几次 即可在O(1)的时间内判断当前牛是否应该转向

sum的求法相当于求滑动定长区间和

 

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <stack>
#include <set>
#include <queue>
#include <vector>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

const int maxn = 5100;

int dir[maxn];
int f[maxn];
int n;

int calc(int k)
{
    memset(f, 0, sizeof(f));

    int res = 0;
    int sum = 0;
    for(int i = 0; i < n - k + 1; i++)
    {
        if((dir[i] + sum) % 2 == 1)
        {
            res++;
            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((dir[i] + sum) % 2 == 1)
            return -1;

        if(i-k+1 >= 0)
            sum -= f[i-k+1];
    }

    return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    scanf("%d", &n);

    char tmp[20];
    for(int i = 0; i < n; i++)
    {
        scanf("%s", tmp);
        if(tmp[0] == 'F')
            dir[i] = 0;
        else
            dir[i] = 1;
    }

    int ans = n+1;
    int ans2;
    for(int k = 1; k <= n; k++)
    {
        int m = calc(k);
        if(m != -1 && m < ans)
        {
            ans = m;
            ans2 = k;
        }
    }

    printf("%d %d\n", ans2, ans);

    return 0;
}

 

posted @ 2015-03-04 19:32  地鼠地鼠  阅读(249)  评论(0)    收藏  举报