牛客练习赛60 C. 操作集锦

Link
题意:
求字符串 \(s\) 中不同的子序列的个数
思路:
\(dp[i,j]\) 为前 \(i\) 个字符中长度为 \(j\) 的不同的子序列的个数
先不考虑哪些是重复的:\(f[i,j]=f[i-1,j]+f[i-1,j-1]\)
再考虑减去重复的子序列:可以发现如果在 \(i\) 前存在 \(s[i]\) 这个字符,设这个位置为 \(t\),长度为 \(j\)\(t\) 结尾的子序列在 \(f[i,j]\) 里被计算了两遍,所以重复的部分为 \(f[t-1][j-1]\)
因此记录下 \(i\) 前第一个 \(s[i]\) 出现的位置,减去重复的部分即可
注意:此题中长度为 \(0\) 的子序列合法
代码:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;
 
const ll mod=1e9+7;
const int N=1010;
char s[N];
ll dp[N][N];
int pre[30];
int main() {
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,k;
    cin>>n>>k;
    cin>>s+1;
    dp[0][0]=1;
    for(int i=1;i<=n;i++) {
        dp[i][0]=1;
        for(int j=1;j<=min(i,k);j++) {
            dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;
            if(pre[s[i]-'a']) dp[i][j]=(dp[i][j]+mod-dp[pre[s[i]-'a']-1][j-1])%mod;
        }
        pre[s[i]-'a']=i;
    }
    cout<<dp[n][k]<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/c4Lnn/p/12596110.html
今日推荐