题解:AT_abc017_4 [ABC017D] サプリメント
AT_abc017_4 [ABC017D] サプリメント 题解
题目大意
给定长度为
思路
这种只往一个方向跳,求方案数的题
则:
这个东西使用前缀和很好维护,那么我们的问题就是如何求
欸,我会,线段树!
我们其实可以直接用双指针
- 将
r 往后移 - 当当前的
lastt_r\ge l 时, 将endd_l 到endd_{lastt_r} 都赋值为r - 1 ,将l 赋值为lastt_r + 1
Code
#include <bits/stdc++.h>
using namespace std;
constexpr int maxn = 100010, modd = 1e9 + 7; // 不要忘记取模!
int n, m, a[maxn];
int dp[maxn], endd[maxn];
int las[maxn], lastt[maxn]; // las[i] 表示 i 上次出现的位置,laastt[i] 表示 a[i] 上次出现的位置
int l, r; // 双指针
int sum[maxn]; // 前缀和
signed main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i], lastt[i] = las[a[i]], las[a[i]] = i; // 求 lastt
l = r = 1;
while (1) {
r++;
if (lastt[t] >= l) { // 如果当前有重复
while (1) {
endd[l] = r - 1;
l++;
if (l == lastt[r] + 1) break;
}
}
if (r == n) break;
}
while (1) {
endd[l++] = n;
if (l == n + 1) break;
} // 别忘了把后面无重复的设为 n
dp[n] = 1;
dp[n + 1] = 1;
sum[n + 1] = 1;
sum[n + 2] = 0;
sum[n] = dp[n] + 1;
for (int i = n - 1; i > 0; i--) {
dp[i] = (sum[i + 1] - sum[endd[i] + 2]) % modd;
sum[i] = (sum[i + 1] + dp[i]) % modd;
} // dp 转移
cout << (dp[1] + modd) % modd << '\n';
return 0;
}