poj---3276Face The Right Way

题意:

  给一个01串,一次操作可以翻转连续的K的值,求最小的操作次数m及其对应的k值

  题目链接

tips:

  1.考虑第i头牛来分析,它的状态跟谁和什么操作有关。

  2.分析题目性质,找到问题求解的步骤,在求解中减小问题的规模。----题目问题肯定有解决流程。

  3.递推的思想

  4.看网上的题解还是鞥启发思路的,书和blog各有其好,结合食用效果最佳。

  5.白书上的递推公式有点坑啊。。

  6.代码中sum保存当前位置的前k-1格的操作数

//先要对问题进行分析,找出求解问题的思路
//将问题的规模逐渐缩小,横推过去
//区间的影响范围和 递推公式的理解
//只记录操作的次数,跟线段树的懒标记有点像
//卡在输入了..然而并不是,是中间有个循环i的赋值错了
//网上的题解对输入的处理是定义了一个字符数组,%s输入,最后只用判断第一位
//用getchar(),把回车字符过滤了也可以
//sum的解释https://blog.csdn.net/thudaliangrx/article/details/50444975
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=5001;
int dir[MAXN];
int f[MAXN];
int n;
int clc(int K){
    memset(f,0,sizeof(f));
    int res=0;
    int sum=0;
    for(int i=0;i+K<=n;i++){
        if(( dir[i]+ sum ) %2 != 0){
            res++;
            f[i]=1;

        }
        sum+=f[i];
        if(i-K+1 >= 0) {
            sum-=f[i-K+1];
        }
    }
    //数组下标是从0开始的,所以第n个元素对应的下标是n-1
    for(int i=n-K+1;i<n;i++){//(N-1)-0...(N-1)-(K-1)...(N-1)-K
        if( (dir[i]+sum)%2 != 0){
            return -1;
        }
        if(i-K+1 >= 0){
            sum-=f[i-K+1];
        }
    }
    return res;
}
int main(){
    while(scanf("%d",&n)!=EOF){
        getchar();
        for(int i=0;i<n;i++){


            /*char x[5];
            scanf("%s",&x);
            if(x[0] == 'B'){
                dir[i]=1;
            }
            else{
                dir[i]=0;
            }
            //getchar();
            */
            char x;
            scanf("%c",&x);
            if(x == 'B'){
                dir[i]=1;
            }
            else{
                dir[i]=0;
            }
            getchar();
        }
        int K=1,M=n;
        for(int k=1;k<= n;k++){
            int m=clc(k);
            if(m >= 0 && M>m){
                M=m;
                K=k;
            }
        }
        printf("%d %d\n",K,M);
    }
    return 0;
}
View Code

 

posted @ 2018-09-22 18:00  SUMay  阅读(92)  评论(0编辑  收藏  举报