返回顶部

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;
    }
    
posted @ 2021-06-08 00:48  Rayotaku  阅读(56)  评论(0编辑  收藏  举报