• Enum:Face The Right Way(POJ 3276)


                    

                    面朝大海,春暖花开

      题目大意:农夫有一群牛,牛排成了一排,现在需要把这些牛都面向正确的方向,农夫买了一个机器,一次可以处理k只牛,现在问你怎么处理这些牛才可以使操作数最小?

      这道题很有意思,其实这道题是著名的开关问题的变种,我们可以用模拟去做,但是总不能一个一个地去翻转,不然就是2^n的复杂度了,我们要想另外一些方法。

      我们知道,如果连续翻转同一片区域其实等于没有反转,再者,在翻转位置一样的情况下,先翻转谁其实没有太打大的关系,所以我们可以规定一个顺序(比如从左到右翻转),如果规定了一个方向翻转以后,我们可以翻转过后的左区域以后都不会受到影响,所以这样我们就可以像矩阵乘法一样把k不断增长来把复杂度降下去O(N^3)(K个长度,每个长度最多操作N个数,每个数翻转K次)但是这样对于N=5000来说还是太大了,我们要继续把复杂度降下去。

      我们利用以前那种偏序集的方法,我们规定一个东西flip[i]:=i~i+k-1的是否需要翻转,如果需要翻转则是1,否则就是0,同时定义背面为1,正面是0

      可以看到

        ∑((i+1)-k+1,i)flip[j]=∑(i-1,i-k+1)flip[j]+flip[i]-flip[i-k+1]

      那么我们就可以不断减去两端的方法来求得flip的值了,这是个常数时间,所以复杂度降为O(N^2)

      

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <functional>
     4 
     5 using namespace std;
     6 
     7 static int dir[5001], if_flip[5001];
     8 
     9 int solve(const int, const int);
    10 
    11 int main(void)//开关问题
    12 {
    13     int cows_sum, ans_k, ans_step, step;
    14     char tmp;
    15     while (~scanf("%d", &cows_sum))
    16     {
    17         getchar();
    18         for (int i = 0; i < cows_sum; i++)
    19         {
    20             scanf("%c", &tmp);
    21             dir[i] = tmp == 'B' ? 1 : 0;//0表示前面,1表示后面
    22             getchar();
    23         }
    24         ans_step = cows_sum; ans_k = 1;
    25         for (int k = 1; k <= cows_sum; k++)
    26         {
    27             step = solve(cows_sum, k);
    28             if (step >= 0 && step < ans_step)
    29             {
    30                 ans_step = step;
    31                 ans_k = k;
    32             }
    33         }
    34         printf("%d %d
    ", ans_k, ans_step);
    35     }
    36     return 0;
    37 }
    38 
    39 int solve(const int cows_sum,const int k)
    40 {
    41     //flip[i]:=i~i+k-1是否进行了翻转,翻转了就是1,否则就是0
    42     int sum = 0, i, ans_step = 0;
    43 
    44     memset(if_flip, 0, sizeof(if_flip));
    45     for (i = 0; i <= cows_sum - k; i++)
    46     {
    47         if ((dir[i] + sum) % 2 == 1)//表明经过一系列翻转(如存在)还是背面朝上,则继续翻转
    48         {
    49             ans_step++;
    50             if_flip[i] = 1;
    51         }
    52         sum += if_flip[i];
    53         if (i - k + 1>= 0)//注意这里是i-k+1!
    54             sum -= if_flip[i - k + 1];
    55     }
    56     for (; i < cows_sum; i++)//检查,剩下的段是不能翻转了(小于k了,所以只用检查一下符不符合规则就好)
    57     {
    58         if ((dir[i] + sum) % 2 == 1)//说明还是有朝上的,说明这样的k是不行的
    59         {
    60             ans_step = -1;
    61             break;
    62         }
    63         else if (i - k + 1>= 0)//注意这里是i-k+1!
    64             sum -= if_flip[i - k + 1];
    65     }
    66     return ans_step;
    67 }

      

  • 相关阅读:
    libevent库的使用方法
    libevent中定时器的使用方法
    最小二乘原理(1)——线性等权重最小二乘
    E: Could not get lock /var/lib/dpkg/lock-frontend
    Ubuntu 18.04源码编译安装OpenCV 4.0步骤
    基于Socket和OpenCV的实时视频传输
    Jetson Nano系列教程3:GPIO
    Jetson Nano 系列教程2:串口调试接口登录Jetson Nano
    推荐 5 款牛逼的代码编辑器
    spring-boot-run 指令是怎么运行 Spring Boot 项目的?
  • 原文地址:https://www.cnblogs.com/Philip-Tell-Truth/p/5152600.html
Copyright © 2020-2023  润新知