• AT3575 101 to 010(DP)


    满分做法:

    这道题蛮难想的,(dp[i])表示到i位置的最大操作数,(11111101)(1011111)这两种情况我们可求出它的最大操作数为长度(-2),并发现整个序列的操作数可以拆分成几个小序列的最大操作做次数之和。

    所以我们要记录(l[i])表示左边离(i)最近的(0)的位置,并得出转移:

    (dp[i]=max(dp[i],dp[l[i-2]]+i-l[i-2]-2)),(dp[i]=max(dp[i],dp[l[i-2]+1]+i-l[i-2]-1-2)) (s[i-1]'0'&&s[i-2]'1')。为什么会是两个呢?

    因为这个序列可能长这样:(111111011111101),这样对于第一个转移来说第二个明显更优,而对于(001111101)这样的序列,第一个更优.

    (dp[i]=max(dp[i],dp[l[i]-2]+i-l[i]+2-2)) (l[i]>1&&s[l[i]-1]=='1'),剩下的直接赋值即可。

    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int maxm=500007;
    char s[maxm];
    int n;
    int dp[maxm];//到i位置的最大操作数 
    int l[maxm];//在左边离i最近的0的位置 
    int main()
    {
     scanf("%d",&n);
     scanf("%s",s+1);
     for(int i=1;i<=n;i++)
     {
      if(s[i]=='1') l[i]=l[i-1];
      else l[i]=i;	
     }
     for(int i=1;i<=n;i++)
     {
       dp[i]=dp[i-1];
       if(s[i]=='1')
       {
         if(s[i-1]=='0'&&s[i-2]=='1')
         {
           dp[i]=max(dp[i],dp[l[i-2]]+i-l[i-2]-2);//100|11111101的贡献为他们的长度-2,
           dp[i]=max(dp[i],dp[l[i-2]+1]+i-l[i-2]-1-2);//11111101|11111101
         }
         else if(l[i]>1&&s[l[i]-1]=='1')
    	 {
    	  dp[i]=max(dp[i],dp[l[i]-2]+i-l[i]+2-2);//101111111
         }
       }
     }
     printf("%d
    ",dp[n]);
     return 0;	
    }
    
  • 相关阅读:
    2019-9-10做题记录
    2019-9-9做题记录
    【HAOI2008】硬币购物
    【SCOI2010】生成字符串
    第18讲——ActiveX控件
    第20讲 HOOK和数据库编程
    第19讲——动态链接库
    2016-5-22 百度之星第三题--瞬间移动
    2016-4-25 完美世界-实习--小萌的包裹
    第3章 拍摄UFO——单一职责原则
  • 原文地址:https://www.cnblogs.com/lihan123/p/11683224.html
Copyright © 2020-2023  润新知