[Codeforces 17C] Balance

Brief Introduction:

给定一个仅由abc组成的字符串,每个字符可以向左右延展,求最终新的平衡字符串的个数。

 

Algorithm:

关键点在于变换前后字符串中字符的相对位置不会发生改变

也就是说,将前后字符串unique后,B是A的子序列

问题转化为求A得子序列数

这样直接使用dp[cur][i][j][k] 配合 next[i][char] 转移即可

 

不过在实际实现中可以不用unique,直接在原字符串上转移也是同样的效果

 

Code:

#include <bits/stdc++.h>

using namespace std;
const int m=51123987;

int n,nxt[155][3],dp[155][55][55][55],res=0;
char dat[155];

bool check(int a,int b,int c)
{
    if(abs(a-b)>1) return false;
    if(abs(a-c)>1) return false;
    if(abs(b-c)>1) return false;
    return true;
}

int main()
{
    cin >> n;
    for(int i=1;i<=n;i++) cin >> dat[i];
    
    for(int i=n;i;i--)
    {
        nxt[i][0]=nxt[i+1][0],nxt[i][1]=nxt[i+1][1];
        nxt[i][2]=nxt[i+1][2],nxt[i][dat[i]-'a']=i;
    }
    
    int most=n/3+2;dp[1][0][0][0]=1;
    for(int cur=1;cur<=n;cur++)
        for(int i=0;i<=most;i++)
            for(int j=0;j<=most;j++)
                for(int k=0;k<=most;k++)
                    if(dp[cur][i][j][k])
                    {
                        if(i+j+k==n && check(i,j,k))   //向答案贡献的条件
                            res=(res+dp[cur][i][j][k])%m;
                        
                        int &a=dp[nxt[cur][0]][i+1][j][k];
                        int &b=dp[nxt[cur][1]][i][j+1][k];
                        int &c=dp[nxt[cur][2]][i][j][k+1];
                        a=(a+dp[cur][i][j][k])%m;
                        b=(b+dp[cur][i][j][k])%m;
                        c=(c+dp[cur][i][j][k])%m;
                    }
    cout << res;
    return 0;
}

 

Review:

抓住不变量解题,发现相对位置不变使用类似 完全背包 的DP解题

posted @ 2018-05-10 17:11  NewErA  阅读(277)  评论(0编辑  收藏  举报