反转问题

反转问题

poj3276

题意:
N头牛排成一列,每头牛或者朝前,或者朝后。为了让所有牛都面向前方,农夫约翰买了一台自动转向的机器。这个机器在购买时就必须设定一个数值K,机器每操作一次恰好使K头连续的扭转向。请求出为了让所有的牛都能面向前方所需要的最少操作次数M和对应的最小K。

限制条件:
1<=N<=5000

思路:
首先,可以确定翻转顺序对结果是没有影响的。其次,可以知道对同一个区间进行两次以上的反转是多余的。因此,我们可以从最左边开始,如果最左边那个需要反转就反转K头连续的牛,在判断第二个是否需要反转…..,这样写的话,复杂度有点高,最差o(n^3)不能解决这个问题。区间反转部分还算很容易优化的。
f[i]:=区间[i,u+K-1] 进行了反转的话就为1,否则为0
这样在考虑第i头牛时,如果

i−1
∑ f [ j] 为奇数的话,则着头牛的方向玉开始方向是相反的(就是看他之前被反转了多少次)。否则方向不
j=i−K+1
变。
由于:
∑(j=(i+1)-K+1,i) f[j] = ∑(j=i-K+1,i-1)f[j] + f[i] - f[i-K+1]
所以这个和每一次都可以在常熟时间内计算出来,复杂度就降为O(N^2)
AC代码:

//
// Created by luozujian on 17-12-2.
//
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 5000+5;
int dir[maxn];     //牛的方向(0:F,1:B)
int f[maxn];   //区间[i,i-k+1]是否进行反转
int n;
//固定k 求最小的操作数  无解返回-1
int calc(int k)
{
    memset(f,0,sizeof(f));
    int res = 0;
    int sum = 0;
    for(int i=0;i+k<=n;i++)
    {
        if((sum+dir[i])%2 !=0)
        {
             //牛面朝后方。
            f[i] = 1;
            res++;
        }
        sum+=f[i];
        if(i-k+1 >= 0)
        {
            sum-=f[i-k+1];
        }
    }
    //检查剩下的牛是否有面朝后方的情况
    for(int i=n-k+1;i<n;i++)
    {
        if((sum+dir[i])%2 !=0)
        {
            return -1;   //无解
        }
        if(i-k+1>=0)
        {
            sum-=f[i-k+1];
        }
    }
    return res;
}
void solve()
{
    int K = 1,M = n;
    for(int k=1;k<=n;k++)
    {
        int m = calc(k);
        if(m>0 && M>m)
        {
            K = k;
            M = m;
        }
    }
    printf("%d %d\n",K,M);
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        char str[2];
        scanf("%s",str);
        printf("%c\n",str[0]);
        if(str[0] == 'B') dir[i] = 1;
        else dir[i] = 0;
    }
    solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值