Educational Codeforces Round 110 (Rated for Div. 2) C. Unstable String (dp)
-
题意:有一\(01\)串,\(?\)既可以表示成\(0\)也可以表示成\(1\),问其所有子串中,问有多少不出现相邻相同字符的子串。
-
题解:根据题意,合法串一定0101这样的,那么当前位置的1/0肯定是从上个位置的0/1转移过来,如果上个位置的字符和当前相同,那么就重新开始。由此可以写出状态转移方程:\(dp[i][0/1]=dp[i-1][1/0]+1\),再去考虑\(?\)的情况,这里我们可以直接从\(dp[i-1][0]\)和\(dp[i-1][1]\)转移过来,但是会有多出来的情况,比如i-1是0,i是?,那么合法情况只有?取1才行,由于我们把0的情况也算上了,所以再减去重复的贡献(1+2+3+4...)即可。
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} ll dp[N][2]; int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int _; cin>>_; while(_--){ string s; cin>>s; int n=(int)s.size(); s=" "+s; rep(i,0,n) dp[i][0]=dp[i][1]=0; ll ans=0; for(int i=1;i<=n;++i){ if(s[i]=='0') dp[i][0]=dp[i-1][1]+1; if(s[i]=='1') dp[i][1]=dp[i-1][0]+1; if(s[i]=='?'){ dp[i][0]=dp[i-1][1]+1; dp[i][1]=dp[i-1][0]+1; } ans+=dp[i][0]; ans+=dp[i][1]; } ll cnt=0; for(int i=1;i<=n;++i){ if(s[i]=='?') cnt++; else{ ans-=(cnt)*(cnt+1)/2; cnt=0; } } ans-=cnt*(cnt+1)/2; cout<<ans<<'\n'; } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮