zoukankan      html  css  js  c++  java
  • 【反转】POJ3276

    Face The Right Way

    题意:N个牛 每个都有一定的方向 B背对 F表示头对着你 给你一个装置 每次可以选择连续的K个牛反转方向 问你如何选择K 使得操作数最少 k也应尽量小. 

    例子:   N=7   BBFBFBB   (F:前面   B:后面)    (红色的为要反转的)   此出K=3  M=3  

    B B F B F B B

    F F B B F B B

    F F F F B B B

    F F F F F F F   成功了

    如果用暴力的方法的话:   考虑N头牛的话最坏情况下要进行N-k+1次反转操作。

    for(k=1;k<=N;k++)

    for(i=1;i<=N;i++)

    for(j=i;j<=i+k;j++)

    因此复杂度为n^3  。

    反转算法:

    定义 f[i]:区间[i,i+k-1]进行反转的话就为1,否则为0

    区间反转部分很好优化: 
    在考虑第i头牛时候,如果i1j=(iK+1)f[j]∑j=(i−K+1)i−1f[j]和为奇数,就说明此时这个牛方向与最初相反。 
    由于 
    ij=(i+1)K+1f[j]∑j=(i+1)−K+1if[j]=i1j=(iK+1)f[j]∑j=(i−K+1)i−1f[j]+f[i]-f[i-K+1]

    所以这个每一次都可以用常数算出来,时间复杂度O(n^2)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int N=5000+10;
    int f[N],dir[N],n;
    int solve(int k){
       int cnt=0,sum=0;//sum为f的和
       memset(f,0,sizeof(f));
       for(int i=1;i<=n-k+1;i++){
        if((dir[i]+sum)%2){
             cnt++;
             f[i]=1;
        }
        sum+=f[i];
        if(i-k+1>=1) sum-=f[i-k+1];
       }
       for(int i=n-k+2;i<=n;i++){//检查剩下的牛有没有朝后面的情况
          if((dir[i]+sum)%2) return n+1;
          if(i-k+1>=1) sum-=f[i-k+1];
       }
       return cnt;
    }
    
    int main(){
       while(~scanf("%d",&n)){
           for(int i=1;i<=n;i++){
              char c;scanf(" %c",&c);
              if(c=='B') dir[i]=1;
           }
           int ansk,ansm=n,t;
           for(int i=1;i<=n;i++){
              t=solve(i);
              if(t<ansm){
                  ansm=t;ansk=i;
              }
           }
           printf("%d %d
    ",ansk,ansm);
       }
    }

    参考:
    常用技巧精选.反转(开关问题) poj3276 3279 3185 1244

    开关问题--反转 poj 3276

  • 相关阅读:
    poj2739
    poj1469
    poj2010
    poj1179
    poj1778
    使用数组实现ArrayList的效果
    zgb老师关于java集合的总结
    jah老师中关于集合的总结
    继承一个类或者是实现一个接口注意点
    5、Iterator迭代器的使用
  • 原文地址:https://www.cnblogs.com/Kohinur/p/9038032.html
Copyright © 2011-2022 走看看