Gym - 101350A-A - Sherlock Bones-DP

妈蛋,开始都没看懂题意,临近结束了才知道题意,只知道是dp。
但是还是没得发现子结构是什么。。
具体思路:
先统计从0到i(截止点是i)的奇数区间和偶数区间。
这个我也不会。。
然后在排除状如 0001 和10000的情况
你会发现,一个0可以会增加一个非法区间,一个1本身就是非法区间。。
所以我第一个初始就调成1,顺带记录1的个数了。。
改成longlong。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
/*昨天写这一道题写失败了。。没有弄清意思,
  这种   类似维护出 一个 dp


*/
const int maxn=200007;
int main()
{     int m;
    long long dp[maxn][2];
     char a[maxn];
     scanf("%d",&m);
      while(m--)
      {     int len;
          memset(dp,0,sizeof(dp));
          memset(a,0,sizeof(a));
           scanf("%d",&len);
             getchar();
             for(int i=0;i<len;i++)
                scanf("%c",&a[i]);
            if(a[0]=='1')
            {   dp[0][0]=1;//0设置为奇数区间的个数
                dp[0][1]=0;
            }
            else
            {   dp[0][0]=0;
                dp[0][1]=1;// 0 构成一个偶数区间.
            }
          for(int i=1;i<len;i++)
          {   if(a[i]=='1')//奇数区间遇1则变。偶数区间不变。
               {  dp[i][0]=dp[i-1][1]+1;
                   dp[i][1]=dp[i-1][0];//偶数区间为以前的奇数区间
               }
              else
              {  dp[i][0]=dp[i-1][0];
                 dp[i][1]=dp[i-1][1]+1;
              }
          }
          /*for(int i=0;i<len;i++)
          {   cout<<"奇数区间"<<endl;
              printf("%d ",dp[i][0]);

          }
          cout<<endl;
          for(int i=0;i<len;i++)
          {  cout<<"偶数区间"<<endl;
              printf("%d ",dp[i][1]);
          }*/
          long long sum=0;
          for(int i=0;i<len;i++)
            sum+=dp[i][0];

      long long  res=1;
      long long all=0;
       for(int i=0;i<len;i++)//这个事删除001 之流。发现每增加一个0,贡献一个非法区间
        {   if(a[i]=='1')
              { all+=res;
                  res=1;//为啥这个初始化为1呢,因为一个1也贡献一个非法的
              }
            else
                res++;
        }
        res=0;
       for(int i=len-1;i>=0;i--)//去掉 100之流。
       {   if(a[i]=='1')
          {  all+=res;
              res=0;
          }
          else res++;

       }
        printf("%lld\n",sum-all);

      }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值