题解 序列

传送门
ARC100F
官方题解

  • 注意形如「求包含一个给定子串(出现位置可以重叠)」的限制中那个「可以重叠」的条件可以这样去掉:
    枚举这个子串的出现位置,剩下的位置任意填
    这样每种合法方案都是会被计算到的
  • 一个有些经典的问题:
    image
    image

部分分暴力DP的话可以利用 \(k\leqslant 4\) 的限制

然后考虑原问题
发现现在不会加上必须是colorful sequence的限制
于是容斥减掉不是的
若给定序列是colorful的不用减

若给定序列元素distinct可以DP:
发现并不关心具体内容,所以尝试DP出在长为 \(n\) 的序列中长为 \(m\) 的distinct序列数量
额外令一个 \(g_{i, j}\) 为这个东西,转移与上面基本相同,在 \(j\geqslant m\)\(+f_{i, j}\) 就行了

若有重复元素可以取出distinct的前缀和后缀分别DP,乘法原理合并即可

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 25010
#define ll long long
// #define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, m;
int a[N], buc[N];
const ll mod=1e9+7;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

bool iscolorful() {
	if (m<k) return 0;
	int cnt=0;
	for (int i=1; i<=k; ++i) if (!buc[a[i]]++) ++cnt;
	if (cnt==k) return 1;
	for (int i=k+1; i<=m; ++i) {
		if (!buc[a[i]]++) ++cnt;
		if (!(--buc[a[i-k]])) --cnt;
		if (cnt==k) return 1;
	}
	return 0;
}

bool distinct() {
	for (int i=1; i<=k; ++i) buc[i]=0;
	for (int i=1; i<=m; ++i) if (buc[a[i]]++) return 0;
	return 1;
}

namespace task1{
	ll f[N][410], g[N][410], fac[N], inv[N], ans;
	ll solve() {
		f[0][0]=1; fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<=k; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<=k; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<=k; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		f[0][0]=1;
		for (int i=1; i<=n; ++i) {
			ll sum=0, sum2=0;
			for (int j=k-1; j; --j) {
				sum=(sum+f[i-1][j])%mod;
				sum2=(sum2+g[i-1][j])%mod;
				f[i][j]=((k-j+1)*f[i-1][j-1]+sum)%mod;
				g[i][j]=((k-j+1)*g[i-1][j-1]+sum2+(j>=m?f[i][j]:0))%mod;
			}
		}
		for (int i=1; i<k; ++i) ans=(ans+g[n][i])%mod;
		return ans*fac[k-m]%mod*inv[k]%mod;
	}
}

namespace task2{
	int cnt[N], len1, len2;
	ll f[N][410], g[N][410], ans;
	ll solve() {
		for (int i=1; i<=k; ++i) cnt[i]=0;
		for (len1=1; !cnt[a[len1]]; ++cnt[a[len1++]]) ;
		for (int i=1; i<=k; ++i) cnt[i]=0;
		for (len2=m; !cnt[a[len2]]; ++cnt[a[len2--]]) ;
		--len1; len2=m-len2;
		// cout<<"len: "<<len1<<' '<<len2<<endl;
		f[0][len1]=g[0][len2]=1;
		for (int i=1; i<=n; ++i) {
			ll sum1=0, sum2=0;
			for (int j=k-1; j; --j) {
				sum1=(sum1+f[i-1][j])%mod;
				sum2=(sum2+g[i-1][j])%mod;
				f[i][j]=((k-j+1)*f[i-1][j-1]+sum1)%mod;
				g[i][j]=((k-j+1)*g[i-1][j-1]+sum2)%mod;
			}
		}
		for (int i=0; i<=n-m; ++i) {
			ll t1=0, t2=0;
			for (int j=1; j<k; ++j) t1=(t1+f[i][j])%mod;
			for (int j=1; j<k; ++j) t2=(t2+g[n-m-i][j])%mod;
			ans=(ans+t1*t2)%mod;
		}
		// cout<<ans<<endl;
		return ans;
	}
}

signed main()
{
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);

	n=read(); k=read(); m=read();
	for (int i=1; i<=m; ++i) a[i]=read();
	if (iscolorful()) printf("%lld\n", ((1ll*(n-m+1)*qpow(k, n-m))%mod+mod)%mod);
	else if (distinct()) printf("%lld\n", ((1ll*(n-m+1)*qpow(k, n-m)-task1::solve())%mod+mod)%mod);
	else printf("%lld\n", ((1ll*(n-m+1)*qpow(k, n-m)-task2::solve())%mod+mod)%mod);

	return 0;
}
posted @ 2022-01-11 20:12  Administrator-09  阅读(6)  评论(0编辑  收藏  举报