Gym 101350A Sherlock Bones
Posted liqgnonqfu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym 101350A Sherlock Bones相关的知识,希望对你有一定的参考价值。
题目大意:
有一个长为N的01数列,记f(i,j)表示从第i位到第j位1的个数,目前需要你统计满足f(i,j)=f(j,k)的(i,j,k)的个数,其中i<j<k。 (3?≤?N?≤?2?×?105)
思路:
//因为它是与左右两边有关,我总想着怎么构造一个树形的dp,然而并不是。我看了这个题解,写的很好https://blog.csdn.net/hao_zong_yin/article/details/79888260。
仅当一个区间有奇数个1才满足条件,我们先找出所有奇数个1的区间,在减去1在一端的(e.g:0001,1000)!用f[i][0]表示到第i位有偶数个1;用f[i][1]表示到第i位有奇数个1。
那么,当前位为0时,f[i][0]=f[i-1][0]+1,f[i][1]=f[i-1][1]因为0本身就构成一个偶数个1的区间;
当前位为1时,f[i][1]=f[i-1][0]+1,f[i][0]=f[i-1][1]因为1本身就构成一个奇数个1的区间;
之后,考虑多算的:
以1为结尾,它之前有几个0,就多算了几个0+1的区间;同样,以1为开头,它之后有几个0,就多算了几个1+0的区间;有几个1,就多算了几个只有1的区间。因此,只用正着for一边在倒着for一边来统计就好。
还有记得long long。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 7 int f[200005][2],T,n; 8 char ch[200005]; 9 long long ans; 10 11 int main() 12 { 13 scanf("%d",&T); 14 for(int I=1;I<=T;I++) 15 { 16 scanf("%d %s",&n,ch+1); 17 memset(f,0,sizeof(f)); 18 for(int i=1;i<=n;i++)//dp 求所有奇数个1的区间; 19 { 20 if(ch[i]==‘0‘) 21 { 22 f[i][0]=f[i-1][0]+1; 23 f[i][1]=f[i-1][1]; 24 } 25 if(ch[i]==‘1‘) 26 { 27 f[i][0]=f[i-1][1]; 28 f[i][1]=f[i-1][0]+1; 29 } 30 } 31 ans=0; 32 for(int i=1;i<=n;i++)ans+=f[i][1]; 33 int cnt=0;//记录0的个数; 34 for(int i=1;i<=n;i++)//出去0+1; 35 { 36 if(ch[i]==‘0‘)cnt++; 37 if(ch[i]==‘1‘) 38 { 39 ans-=cnt; 40 cnt=0; 41 } 42 } 43 cnt=0; 44 for(int i=n;i>=1;i--)// 出去1+0; 45 { 46 if(ch[i]==‘0‘)cnt++; 47 if(ch[i]==‘1‘) 48 { 49 cnt++; //顺便除去1的; 50 ans-=cnt; 51 cnt=0; 52 } 53 } 54 printf("%I64d ",ans); 55 } 56 return 0; 57 }
以上是关于Gym 101350A Sherlock Bones的主要内容,如果未能解决你的问题,请参考以下文章
Sherlock之Instructions指令介绍(Sherlock Version: 7.2.5.1 64-bit)