1. 程式人生 > >Gym 101350A Sherlock Bones

Gym 101350A Sherlock Bones

題解 gym ret closed src tdi 因此 sed 怎麽

題目大意:

有一個長為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\n%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\n",ans); 55 } 56 return 0; 57 }
View Code

Gym 101350A Sherlock Bones