POJ 3276 Face The Right Way(开关转换)

题意:

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

分析:

首先,交换区间反转的顺序对结果是没有影响的。此外,可以知道对同一个区间进行两次以上的反转是多余的,由此,问题就转化成了求需要被反转的区间的集合。于是我们先考虑一下最左端的牛。包含这头牛的区间只有一个,因此如果这头牛面朝前方,我们就能知道这个区间不需要反转。

反之,如果这头牛面朝后方,对应的区间就必须进行反转了。而且在此之后这个最左的区间就再也不需要考虑了。这样一来,通过首先考虑最左端的牛,问题的规模就缩小了1.不断的重复下去,就可以无需搜索求出最少所需的反转次数了。


详细可以看挑战里的分析。




#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N= 2000;
const int maxn = 1e4+10;
const int maxm = 1e7+10;
const int MOD = 1e9+7;
int dir[maxn],f[maxn];                        //dir方向
int n;
int work(int k)                               //精华部分  
{
    memset(f,0,sizeof(f));
    int cnt = 0,sum = 0;
    for(int i = 0; i + k <= n; i++)
    {
        if ((sum + dir[i])%2 != 0)
        {
            cnt++;
            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 != 0) return -1;
        if (i-k+1 >= 0) sum -= f[i-k+1];
    }
   return cnt;
}
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);

    while(scanf("%d",&n)!=EOF)
    {
        for(int i = 0; i < n; i++)
        {
            char ch;
            cin>>ch;
            if (ch == 'B') dir[i] = 1;
            else dir[i] = 0;
        }
       int k = 1, m = n;
       for(int i = 1; i <= n; i++)             //枚举长度k
       {
           int tt = work(i);
           if (tt >= 0 && tt < m) m = tt,k = i;
       }
       printf("%d %d\n",k,m);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值