计蒜客T42256硬币--题解

Posted huoshihongqwq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计蒜客T42256硬币--题解相关的知识,希望对你有一定的参考价值。

题面

题面
原题面:
小 B 面前的桌子上有 (n) 个硬币,(0) 表示正面,(1) 表示反面,只有当这 (n) 个硬币都是 (0) 朝上的时候这个他才能把这些钱收起来。现在他可以一个这样的操作来翻硬币,他选择一个 (x),把 (1)(x) 位置上的硬币都翻面,他现在想知道最少需要多少次操作能使所有硬币正面朝上

题目描述

给定一个长度为(n)(01)(s)(s_i in { 0,1 })
每次可以选择一个(x),使得([1,x])之间的所有元素反转,即(0 ightarrow 1,1 ightarrow 0)
问最少需要多少次可以把所有的元素变为(0)

输入格式

第一行:一个非负整数(n),表示串(s)的长度。
第二行:串(s),第(i)个字符表示(s_i)

输出格式

输出最小的操作次数。

样例输入(1)

4
1001

样例输出(1)

3

样例输入输出(1)解释

第一次操作:(x = 4),串(s)变为(0110)
第二次操作:(x = 3),串(s)变为(1000)
第三次操作:(x = 1),串(s)变为(0000)
可以证明,最小需要(3)次可以将(s)中所有元素变为(0)。且没有一种方案比这种方案更优。

样例输入(2)

5
10010

样例输出(2)

3

样例输入输出(2)解释

第一次操作:(x = 4),串(s)变为(01100)
第二次操作:(x = 3),串(s)变为(10000)
第三次操作:(x = 1),串(s)变为(00000)
可以证明,最小需要(3)次可以将(s)中所有元素变为(0)。且没有一种方案比这种方案更优。

数据规模与约定

对于(30\%)的数据:(1 leq n leq 20)
对于另(20\%)的数据:所有(s_i)都相等
对于(100\%)的数据:(1 leq n leq 10^6)

题解

慢慢挖掘题目性质。
性质1:答案与操作的顺序无关
证明
显而易见,无需证明

(p_i)(s)转化成目标串的过程中,(s_i)被反转的
最小次数
(p_i)一定是
非负整数

性质2
(s_i = 0)时,(p_i)一定是偶数;
(s_i = 1)时,(p_i)一定是奇数;
证明
显然,不用证明。

性质3(p_1)就是(s)转化为目标串的最小操作次数
证明
由于每次操作都是([1,x]),都动了(s_1)
所以(s_1)被反转的次数就是转化为目标串的最小次数。

性质4(forall p_i geq p_{i + 1} (1 leq i leq n)),即(p)单调不增
证明
对于(i,j)(i < j)
(p_i geq p_j)
因为每次动到(j)的时候,(i)肯定被动到了。
所以(p_i geq p_j)
即,(p)单调不增。
***
性质5(max _{1 leq i leq n} { p_i} = p_1)
证明
性质4得来。

结合以上所有性质。
目标是要求操作次数最小,所以就是要求(p_1)最小。
要求(p_1)最小,由于
性质5所以目标就是要求这个序列(p)尽量小
这样才能保证最大的最小。

因为(p_i)是非负整数,我们考虑倒推。
并且要保证不破坏以上所有性质。
(s_n = 0)时,显然,(p_n = 0)
(s_n = 1)时,显然,(p_n = 1)
我们开始递推:
对于第(i (1 leq i leq n-1))
如果(s_i = s_{i+1}),则,(p_i = p_{i+1})
如果(s_i ot ={s_{i+1}}),则,(p_i = p_{i+1} + 1)
***
综上,递推完之后,(p_1)就是答案。
代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
#define maxn 1000000
int p[maxn + 10];
int main()
{
    int n;
    string s;
    cin>>n>>s;
    if(s[s.size() - 1] == '0')
    {
        p[s.size() - 1] = 0;
    }else
    {
        p[s.size() - 1] = 1;
    }//判断最后一位
    for(int i = s.size() - 2;i >= 0;i--)//倒推
    {
        if(s[i] == s[i + 1])
        {
            p[i] = p[i + 1];
        }else
        {
            p[i] = p[i + 1] + 1;
        }//递推公式
    }
    cout<<p[0];//输出第一个的p
    return 0;
}

复杂度(Theta (n))

以上是关于计蒜客T42256硬币--题解的主要内容,如果未能解决你的问题,请参考以下文章

计蒜客后缀字符串题解

计蒜客 17414 Exponial 指数降幂公式

计蒜客--无脑博士的试管们

[计蒜客] ACM-ICPC 2018 南京赛区网络预赛 | 部分题解 | 线段树 + 线性筛 + 最短路

计蒜客 17412 Card Hand Sorting 最长公共子序列

计蒜客 UCF 2015