披着信息的皮的数学题
Posted hhhhalo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了披着信息的皮的数学题相关的知识,希望对你有一定的参考价值。
题目描述
您有一个字符串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 }
这就是一个数学题...
以上是关于披着信息的皮的数学题的主要内容,如果未能解决你的问题,请参考以下文章