zoukankan      html  css  js  c++  java
  • 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;	
    }
    
  • 相关阅读:
    如何将cordova导入Android studio,只需两步即可
    Cordova 教程 学习步骤-从零基础开始
    特效插件
    jq 命名空间
    input聚焦后光标移动至末尾
    时间常用api
    jq 便捷api jq 常用 api jq 快捷 api
    键盘事件
    创建爬网规则
    SharePoint 2013 本地开发解决方案以及程调试(真的可以)
  • 原文地址:https://www.cnblogs.com/lihan123/p/11683224.html
Copyright © 2011-2022 走看看