题面
给定两个整数 n , k n,k n,k,以及一个长度为 m m m 的整数序列 a a a,其中 1 ≤ a i ≤ k 1\leq a_i\leq k 1≤ai≤k 。
如果一个由 1 ∼ k 1\sim k 1∼k 组成的整数序列中,存在一个长度为 k k k 的连续子序列,满足这 k k k 个数字在子序列中都出现过,那这个序列就被称为“彩色序列”。
对于一个“彩色序列”,我们可以计算出 a a a 作为它的连续子序列的出现次数(出现位置可以部分重叠)。而你需要做的,就是计算出对于所有长度为 n n n 的彩色序列,这个出现次数的和是多少。答案对 1 0 9 + 7 10^9+7 109+7 取模。
1 ≤ m ≤ n ≤ 25000 , k ≤ 400 1\leq m\leq n\leq25000,~k\leq400 1≤m≤n≤25000, k≤400 。
题解
我知道了,动态规划题果然是最不好写题解的,稍不注意就讲得云里雾里。
首先用一个小容斥,朴素序列的出现次数和,减去非“彩色序列”的出现次数和。
朴素序列的出现次数和很简单,我们考虑在某个位置出现时,总的序列方案数。答案是 k n − m ⋅ ( n − m + 1 ) k^{n-m}\cdot(n-m+1) kn−m⋅(n−m+1) 。
接下来分情况讨论,如果 a a a 本身就是个“彩色序列”,那么非“彩色序列”中的出现次数和就是 0 。
否则,我们先求出一些有用的值来。设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 为长度为
i
i
i 、末尾一段不相同数字长度为
j
j
j 的非“彩色序列”个数。那么有两种转移:末尾添加一个在
[
i
−
j
+
1
,
i
]
[i-j+1,i]
[i−j+1,i] 中未出现的数字,使
j
j
j 变大,或者添加一个在此区间中出现过的数字,使
j
j
j 分别变为
1
∼
j
1\sim j
1∼j 。容易得到状态转移方程:
d
p
[
i
]
[
j
]
=
(
k
−
j
+
1
)
⋅
d
p
[
i
−
1
]
[
j
−
1
]
+
∑
j
′
=
j
k
−
1
d
p
[
i
−
1
]
[
j
′
]
dp[i][j]=(k-j+1)\cdot dp[i-1][j-1]+\sum_{j'=j}^{k-1}dp[i-1][j']
dp[i][j]=(k−j+1)⋅dp[i−1][j−1]+j′=j∑k−1dp[i−1][j′]
用后缀和优化,记 s u m [ i ] [ j ] = ∑ j ′ = j k − 1 d p [ i ] [ j ′ ] sum[i][j]=\sum_{j'=j}^{k-1}dp[i][j'] sum[i][j]=∑j′=jk−1dp[i][j′] ,后面会有用。
如果
a
a
a 中存在相等的数字,意味着出现
a
a
a 的序列左边和右边互不影响。我们可以令
a
a
a 左边最长一段互不相同的数串长度为
l
l
l ,右边同理,记为
r
r
r ,那么
a
a
a 在非彩色序列中的出现次数和即为
∑
i
=
0
n
−
m
s
u
m
[
i
+
l
]
[
l
]
A
(
k
,
l
)
⋅
s
u
m
[
n
−
m
−
i
+
r
]
[
r
]
A
(
k
,
r
)
\sum_{i=0}^{n-m} \frac{sum[i+l][l]}{A(k,l)}\cdot\frac{sum[n-m-i+r][r]}{A(k,r)}
i=0∑n−mA(k,l)sum[i+l][l]⋅A(k,r)sum[n−m−i+r][r]
除去排列数是因为 a a a 中这些位置都是确定的。
如果
m
<
k
m<k
m<k 且
a
a
a 中所有数字都不同,也即是说,
a
a
a 的左边和右边可能一起构成一个“彩色段”,那么,我们就枚举包含
a
a
a 的“彩色段”往左和往右分别延申多长。不难得到非彩色出现次数和为
∑
i
=
m
n
∑
j
=
m
k
−
1
d
p
[
i
]
[
j
]
A
(
k
,
m
)
⋅
s
u
m
[
n
−
i
+
j
]
[
j
]
A
(
k
,
j
)
\sum_{i=m}^n\sum_{j=m}^{k-1}\frac{dp[i][j]}{A(k,m)}\cdot \frac{sum[n-i+j][j]}{A(k,j)}
i=m∑nj=m∑k−1A(k,m)dp[i][j]⋅A(k,j)sum[n−i+j][j]
具体怎么得来的可以自己算算。我也只能说“要多独立思考”之类的话了。
时间复杂度 O ( n k ) O(nk) O(nk) 。
CODE
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 25005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
int xchar() {
static const int maxn = 1000000;
static char b[maxn];
static int pos = 0,len = 0;
if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
if(pos == len) return -1;
return b[pos ++];
}
//#define getchar() xchar()
LL read() {
LL f = 1,x = 0;int s = getchar();
while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
if(!x) {putchar('0');return ;}
if(x<0) putchar('-'),x = -x;
return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}
const int MOD = 1000000007;
int n,m,s,o,k;
int pw[MAXN];
int a[MAXN];
int c[MAXN];
int dp[MAXN][405],sm[MAXN][405];
int fac[MAXN],inv[MAXN],invf[MAXN];
int A(int n,int m) {
if(m < 0 || m > n) return 0;
return fac[n] *1ll* invf[n-m] % MOD;
}
int invA(int n,int m) {
if(m < 0 || m > n) return 0;
return invf[n] *1ll* fac[n-m] % MOD;
}
int main() {
n = read();k = read();m = read();
pw[0] = 1;
for(int i = 1;i <= n;i ++) pw[i] = pw[i-1] *1ll* k % MOD;
fac[0]=fac[1]=inv[0]=inv[1]=invf[0]=invf[1]=1;
for(int i = 2;i <= max(n,k);i ++) {
fac[i] = fac[i-1] *1ll* i % MOD;
inv[i] = (MOD - inv[MOD%i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
int ct = 0,flag = 0;
for(int i = 1;i <= m;i ++) {
a[i] = read();
c[a[i]] ++; if(c[a[i]] == 1) ct ++;
if(i > k) {
c[a[i-k]] --;
if(c[a[i-k]] == 0) ct --;
}
if(ct == k) flag = 1;
}
int ans = pw[n-m] *1ll* (n-m+1) % MOD;
if(flag) {
AIput(ans,'\n');
return 0;
}
dp[1][1] = k; sm[1][1] = k;
for(int i = 2;i <= n;i ++) {
for(int j = k-1;j > 0;j --) {
if(j+1 < k) (dp[i][j+1] += dp[i-1][j] *1ll* (k-j) % MOD) %= MOD;
(dp[i][j] += sm[i-1][j]) %= MOD;
}
for(int j = k-1;j > 0;j --)
sm[i][j] = (sm[i][j+1] + dp[i][j]) % MOD;
}
int l = 0,r = 0;
memset(c,0,sizeof(c));
while(l < m && !c[a[l+1]]) c[a[++ l]] = 1;
memset(c,0,sizeof(c));
while(r < m && !c[a[m-r]]) c[a[m-r]] = 1,r ++;
if(l < m) {
int as = 0;
for(int i = 0;i <= n-m;i ++) {
int aa = i+l,bb = n-m-i+r;
(as += (sm[aa][l]*1ll*invA(k,l)%MOD) *1ll* (sm[bb][r]*1ll*invA(k,r)%MOD) % MOD) %= MOD;
}
(ans += MOD-as) %= MOD;
}
else {
int as = 0;
for(int i = m;i <= n;i ++) {
for(int j = m;j < k && j <= i;j ++) {
(as += (dp[i][j]*1ll*invA(k,m)%MOD) *1ll* (sm[n-i+j][j]*1ll*invA(k,j)%MOD) % MOD) %= MOD;
}
}
(ans += MOD-as) %= MOD;
}
AIput(ans,'\n');
return 0;
}