码迷,mamicode.com
首页 > 其他好文 > 详细

计蒜客T42256硬币--题解

时间:2019-12-27 21:38:55      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:com   顺序   没有   inline   序列   strong   href   size   题目   

题面

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

题目描述

给定一个长度为\(n\)\(01\)\(s\)\(s_i \in \{ 0,1 \}\)
每次可以选择一个\(x\),使得\([1,x]\)之间的所有元素反转,即\(0 \rightarrow 1,1 \rightarrow 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 \not ={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硬币--题解

标签:com   顺序   没有   inline   序列   strong   href   size   题目   

原文地址:https://www.cnblogs.com/huoshihongqwq/p/12109634.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!