• 披着信息的皮的数学题


    题目描述

    您有一个字符串a1,a2,…,ana1,a2,…,an,由零和一组成。

    我们将连续元素ai,ai + 1,...,ajai,ai +1,...,aj(1≤i≤j≤n1≤i≤j≤n)的序列称为字符串aa的子字符串。

    您可以多次应用以下操作:

    选择一个字符串aa的子字符串(例如,您可以选择整个字符串)并反转它,为此支付xx个硬币(例如,«0101101»→→«0111001»);
    选择字符串aa的一些子字符串(例如,您可以选择整个字符串或仅一个符号),然后将每个符号替换为相反的一个符号(零替换为一个,而一个替换为零),为此支付yy个硬币(例如,«0101101»→→«0110001»)。
    您可以按任何顺序应用这些操作。允许将操作多次应用于同一子字符串。

    您需要花费最少的硬币数量才能得到仅包含一个的字符串?


    输入值
    输入的第一行包含整数nn,xx和yy(1≤n≤300000,0≤x,y≤1091≤n≤300000,0≤x,y≤109)—字符串的长度,第一次操作的成本(反向子串)和第二个操作的成本(反向子串的所有元素)。

    第二行包含长度为nn的字符串aa,由零和一组成。

    输出量
    打印一个整数-获得只包含1的字符串所需的最低总操作成本。如果不需要执行任何操作,请打印00。


    例子
    输入值
    5 1 10
    01000
    输出量
    11


    输入值
    5 10 1
    01000
    输出量
    2


    输入值
    7 2 3
    1111111
    输出量
    0


    注意
    在第一个示例中,首先需要反转子字符串[1…2] [1…2],然后需要反转子字符串[2…5] [2…5]。

    然后,字符串更改如下:

    «01000»→→«10000»→→«11111»。

    运营总成本为1 + 10 = 111 + 10 = 11。

    在第二个示例中,首先需要反转子字符串[1…1] [1…1],然后需要反转子字符串[3…5] [3…5]。

    然后,字符串更改如下:

    «01000»→→«11000»→→«11111»。

    总成本为1 + 1 = 21 + 1 = 2。

    在第三个示例中,字符串已经仅包含一个,因此答案为0。


    思路分析:

      看这道题,脑子里立马就蹦出了DP,前两道题也都是DP,就坚信这道题得这么做了,然后就懵了

      这道题看起来简洁明了,就是一个只有0和1的字符串,然后对其进行两种操作:区间内前后翻转和把区间内0全变为1。然后求把整个字符串全变为1的最小代价。

      恶心的地方就在这两种操作都可以执行上了,有点无从下手。

      没办法,分析样例。不难发现,可以对数据进行分组,即把多个连在一起的0或1视为一个整体进行处理(显然这样可以尽可能少的处理,代价最小),然后对每组0进行考虑,这时候的字符串形式就是类似于0101010……这样的

      我们的最终目的是要把0变为1,你再怎么换,你也少不了变为0的操作——划重点,代码会体现

      我们考虑每两个相邻的0101,发现有两种方法处理:(1)转一下前面的01,变为1001;然后进行修改,变为1111;(2)进行两次修改,变为1111;

      我们发现,其中都有一次修改操作,那我们比较另一个不同的即可,显然谁代价小选哪个,不管你选哪个,都不需要再考虑这前面的一组,如果你变为1了,显然不用再管了,如果你选择了转换,那前面的0和后面的0就成一组0了,接下来再只考虑后面的就可以了。如果你着这样我们就合并了两个相邻的;

      接下来,数组还是101010……的形式,继续进行如下操作,每组01都是这样,那就简单了,如果有n组01,我们把最后一次转化为1的操作单独拿出来,剩下的n-1组我们只需进行(n-1)次的单一操作——两种操作哪个小选哪个。

    配合代码理解(不懂一定要自己模拟一遍样例,体会一下过程):

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int maxn = 3e5+10;
     7 char a[maxn];
     8 long long tot;
     9 int main(){
    10     long long n,x,y;scanf("%lld%lld%lld ",&n,&x,&y);
    11     scanf("%s",a+1);
    12     a[0] = '1';
    13     for(int i = 1; i <= n;i++){
    14         if(a[i] == '0' && a[i-1] == '1')tot++; //出现不相邻的0,就多了一组01,否则与前面的0为同一组
    15     }
    16     if(tot == 0)printf("0");
    17     else printf("%lld",min(x,y) * (tot-1) + y); //前tot-1组,单一操作合并为一组,最后再加上一次统一修改的操作
    18     return 0;
    19 }

    这就是一个数学题...

  • 相关阅读:
    《软件测试自动化之道》读书笔记 之 底层的Web UI 测试
    《软件测试自动化之道》读书笔记 之 基于Windows的UI测试
    《软件测试自动化之道》读书笔记 之 基于反射的UI测试
    MS UI Automation Introduction
    Server-Side UI Automation Provider
    Client-Side UI Automation Provider
    Server-Side UI Automation Provider
    河边的苹果
    CommonJS和AMD/CMD
    webpack
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/12681304.html
Copyright © 2020-2023  润新知