C. The Fair Nut and String 遞推分段形dp
阿新 • • 發佈:2019-05-01
一段 題意 == and its set i+1 之間 else if
而如果多段組合的話 第三段既可以和第二段組合 也可以和第二段+第一段組合
第二段+第一段就是 在算第三段之前的合法選擇數,而第三段和第二段 同第一段和第二段的算法相同
所以遞推求解即可 而分段的時候如果字母不是b 直接忽略就行了(因為只是\({\exists}s[p_j]==b)\)所以不會幹擾a和a的組合可以忽略,相當於歸到一段a中但是這一段a的數量不變
ps:記得開long long
C. The Fair Nut and String 遞推分段形dp
題意
給出一個字符串選擇一個序列\({p_1,p_2...p_k}\)使得
對於任意一個\(p_i\) , \(s[p_i]==a\)
對於任意一個\(p_{i}<j<p_{i+1}\)來說 \({\exists}s[p_j]==b\)
思路
所以我們可以得知 我們需要選擇一系列a 使得a和a之間只能是b
那麽我們就可以對a進行分段處理
例如aaaabaaaa 右面與前面組合 只能選擇後面一大串a的前綴和前面一大串a的後綴組合才合法
也就是一共有 num[1]*num[2]中組合 其中num[i] 表示第i段有多少個a
第二段+第一段就是 在算第三段之前的合法選擇數,而第三段和第二段 同第一段和第二段的算法相同
所以遞推求解即可 而分段的時候如果字母不是b 直接忽略就行了(因為只是\({\exists}s[p_j]==b)\)所以不會幹擾a和a的組合可以忽略,相當於歸到一段a中但是這一段a的數量不變
ps:記得開long long
#include<bits/stdc++.h> #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;i++) #define MS(arr,arr_value) memset(arr,arr_value,sizeof(arr)) #define F first #define S second #define pii pair<int ,int > #define mkp make_pair #define pb push_back #define arr(zzz) array<ll,zzz> using namespace std; typedef long long ll; const int maxn=3e5+5; int n,m,y; const int mod=1e9+7; char s[maxn]; int main(){ scanf("%s",s+1); int len=strlen(s+1); long long ans=0; for(int i=1;i<=len;i++){ if(s[i]=='a')ans++; } ll flag=0; ll tmp=0; int cnt=0; ll x=0; ll fixsum=0; ll lastsum=0; int ok=0; for(int i=1;i<=len;i++){ if(s[i]=='a'){ flag++; } else if(s[i]=='b'){ if(flag){ cnt++; tmp+=flag*fixsum; tmp%=mod; //ll zzzz=lastsum; //lastsum=tmp; tmp+=lastsum*flag; tmp%=mod; lastsum=tmp; fixsum+=flag; fixsum%=mod; flag=0; } } if(s[i]=='b')ok=0; else if(s[i]=='a')ok=1; } if(ok){ cnt++; tmp+=flag*fixsum; tmp%=mod; //ll zzzz=lastsum; //lastsum=tmp; tmp+=lastsum*flag; tmp%=mod; lastsum=tmp; fixsum+=flag; fixsum%=mod; flag=0; } if(cnt>=2)ans+=tmp; ans%=mod; cout<<ans<<endl; return 0; }
C. The Fair Nut and String 遞推分段形dp