题解:P9049 [PA 2021] Mopadulo
__biu_biu_biu__ · · 题解
将长度为
n 的序列A 划分成若干段,使得每一段的和模10^9+7 都是偶数,求划分方案数。答案对10^9+7 取模。1\le n\le 3\times 10^5 。
考虑
有转移
这个转移用前缀和优化是
注意到
- 如果
f(1,i)>f(1,j) 且f(1,i) 与f(1,j) 相同奇偶性,则f(j+1,i) 是偶数。 - 如果
f(1,i)<f(1,j) 且f(1,i) 与f(1,j) 不相同奇偶(因为要加上10^9+7 变成正数,奇偶会改变)则f(j+1,i) 是偶数。
因此考虑对
:::info[代码]
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5, mod = 1e9 + 7;
int n, s[N], dp[N], o[N];
int summ[N], m;
int sum[2][N << 2];
int tot[2];
void upd(int fg, int p, int k, int l, int r, int rt) {
if (l == r) {
sum[fg][rt] = (sum[fg][rt] + k) % mod;
return;
}
int mid = l + r >> 1;
if (p <= mid) upd(fg, p, k, l, mid, rt << 1);
else upd(fg, p, k, mid + 1, r, rt << 1 | 1);
sum[fg][rt] = (sum[fg][rt << 1] + sum[fg][rt << 1 | 1]) % mod;
}
int qry(int fg, int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return sum[fg][rt];
int mid = l + r >> 1, res = 0;
if (L <= mid) res = (res + qry(fg, L, R, l, mid, rt << 1)) % mod;
if (R > mid) res = (res + qry(fg, L, R, mid + 1, r, rt << 1 | 1)) % mod;
return res;
}
int main() {
cin >> n;
summ[0] = s[0] = 0; o[0] = 0;
for (int i = 1, a; i <= n; ++i) {
cin >> a;
s[i] = (s[i - 1] + a) % mod;
o[i] = s[i] & 1;
summ[i] = s[i];
}
sort(summ, summ + n + 1);
m = unique(summ, summ + n + 1) - summ;
for (int i = 0; i <= n; ++i)
s[i] = lower_bound(summ, summ + m, s[i]) - summ + 1;
dp[0] = 1;
upd(0, s[0], dp[0], 1, m, 1);
tot[0] = 1;
for (int i = 1; i <= n; ++i) {
int anss1 = qry(o[i], 1, s[i], 1, m, 1);
int anss2 = (tot[o[i] ^ 1] - qry(o[i] ^ 1, 1, s[i], 1, m, 1) + mod) % mod;
dp[i] = (anss1 + anss2) % mod;
upd(o[i], s[i], dp[i], 1, m, 1);
tot[o[i]] = (tot[o[i]] + dp[i]) % mod;
}
cout << dp[n] << '\n';
return 0;
}
:::