题目链接
这种矩阵优化
dp
d
p
的题原来做过但还是做少了…
不过前面的暴力
dp
d
p
还是很好想的啊
我们考虑设
f[i]
f
[
i
]
为以
i
i
结尾的子序列方案数,那么转移的时候每次选取最小的, 令
f[x]=1+∑ni=1f[i]
f
[
x
]
=
1
+
∑
i
=
1
n
f
[
i
]
即可
可以发现这是一个线性的转移方程,那么直接矩乘优化即可
时间复杂度
O(n+k3logm)
O
(
n
+
k
3
l
o
g
m
)
Codes
#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define PII pair<int, int>
#define mp make_pair
#define int long long
using namespace std;
const int maxn = 1e6 + 10, mod = 1e9 + 7, maxk = 100 + 3;
int n, m, k, a[maxn], f[maxk], sum, lst[maxk], rk[maxk];
void add(int &x, int y) {
x += y;
if(x >= mod)
x -= mod;
if(x < 0)
x += mod;
}
void File() {
freopen("sequence.in", "r", stdin);
freopen("sequence.out", "w", stdout);
}
void Init() {
scanf("%lld%lld%lld", &n, &m, &k);
For(i, 1, n)
scanf("%lld", &a[i]);
For(i, 1, n) {
lst[a[i]] = i;
int tmp = f[a[i]];
f[a[i]] = sum + 1;
add(sum , f[a[i]]);
add(sum, -tmp);
}
}
namespace BF {
void Solve() {
priority_queue<PII, vector<PII>, greater<PII> > q;
For(i, 1, k) q.push(mp(lst[i], i));
For(i, 1, m) {
PII x = q.top(); q.pop();
lst[x.second] = n + i;
int tmp = f[x.second];
f[x.second] = sum + 1;
add(sum, f[x.second]);
add(sum, -tmp);
q.push(mp(lst[x.second], x.second));
}
printf("%lld\n", sum);
}
}
namespace Sub7 {
struct Martix {
int n, m;
int a[maxk][maxk];
}now, zhuan, ret;
Martix Mul(Martix A, Martix B) {
Martix res;
res.n = A.n, res.m = B.m;
For(i, 1, A.n)
For(j, 1, B.m) {
res.a[i][j] = 0;
For(k, 1, A.m)
(res.a[i][j] += A.a[i][k] * B.a[k][j] % mod) %= mod;
}
return res;
}
void qpow(int x) {
while(x) {
if(x & 1)
ret = Mul(ret, zhuan);
x >>= 1, zhuan = Mul(zhuan, zhuan);
}
}
void Solve() {
priority_queue<PII, vector<PII>, greater<PII> > q;
For(i, 1, k) q.push(mp(lst[i], i));
For(i, 1, m) {
PII x = q.top();
if(x.first) {
m -= i - 1;
break;
}
q.pop();
lst[x.second] = n + i;
int tmp = f[x.second];
f[x.second] = sum + 1;
add(sum, f[x.second]);
add(sum, -tmp);
q.push(mp(lst[x.second], x.second));
}
now.n = 1, now.m = k + 1, now.a[1][1] = 1;
For(i, 2, k + 1) {
PII x = q.top(); q.pop();
now.a[1][i] = f[x.second];
}
zhuan.a[1][1] = 1, zhuan.n = k + 1, zhuan.m = k + 1;
For(i, 2, k) zhuan.a[i + 1][i] = 1;
For(i, 1, k + 1) zhuan.a[i][k + 1] = 1;
ret.n = k + 1, ret.m = k + 1;
For(i, 1, k + 1)
ret.a[i][i] = 1;
qpow(m + 1);
now = Mul(now, ret);
printf("%lld\n", now.a[1][k + 1] - 1);
}
}
signed main() {
// File();
Init();
if(m <= 1e6)
BF::Solve();
else
Sub7::Solve();
return 0;
}
代码有点丑但也不想改了==