题解 P7888 「MCOI-06」Distinct Subsequences

此做法对字符集大小没有限制。也就是说,这道题可以加强,将字符串改为数列。

一个字符串的价值为该串的本质不同非空子序列个数。如果直接给定一个字符串,怎么求它的价值?我们考虑这样一个算法:

定义 \(det[x]\) 表示以字符 \(x\) 结尾的子序列个数。那么从 \(1\) 开始依次扫过去,对于扫到的每个字符 \(x\),我们只要把 \(det[x]\) 替换为 \(sum+1\) 就行了,\(sum\) 表示当前所有 \(det\) 的和。

也就是 \(x\) 可以和任何一组拼接形成字符串,也可以自己单独形成。

考虑这个问题,要求所有子序列的价值和。如果转化为期望,就是对于扫到的每个 \(x\),随机选择更新 \(det[x]\) 或者不更新,求最后的期望 \(sum\)

对于此处的期望,容易发现怎么做的概率都是相等的,因此可以直接相加取平均数。

得出期望之后乘上 \(2\)\(|S|\) 次方就行了。

代码很好写。目前最优解,23ms。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+5;
char a[N];
const ll mod=1e9+7,inv2=500000004;
ll n,sum,tot=1,det[30];
inline void add(int x)
{
	ll tmp=det[x];
	det[x]=(sum+1+det[x])*inv2%mod;
	sum=(sum+sum-tmp+sum+1)*inv2%mod;
	sum=(sum+mod)%mod;
}
int main()
{
	scanf("%s",a+1);
	n=strlen(a+1);
	for (int i=1;i<=n;i++) add(a[i]-'a'),tot=(tot*2)%mod;
	cout << sum*tot%mod << endl;
	return 0;
}
posted @ 2022-01-26 14:34  Little09  阅读(86)  评论(0)    收藏  举报