P2344 奶牛抗议 离散化+前缀和+动态规划+树状数组
【题目背景】
Generic Cow Protests, 2011 Feb
【题目描述】
约翰家的N 头奶牛正在排队游行抗议。一些奶牛情绪激动,约翰测算下来,排在第i 位的奶牛的理智度为Ai,数字可正可负。
约翰希望奶牛在抗议时保持理性,为此,他打算将这条队伍分割成几个小组,每个抗议小组的理智度之和必须大于或等于零。奶牛的队伍已经固定了前后顺序,所以不能交换它们的位置,所以分在一个小组里的奶牛必须是连续位置的。除此之外,分组多少组,每组分多少奶牛,都没有限制。
约翰想知道有多少种分组的方案,由于答案可能很大,只要输出答案除以$1000000009$ 的余数即可。
【输入格式】
• 第一行:单个整数N,$1 ≤ N ≤ 100000$
• 第二行到第N + 1 行:第i + 1 行有一个整数Ai,$−10^5 ≤ Ai ≤ 10^5$
【输出格式】
单个整数:表示分组方案数模$1000000009$ 的余数
说明:
解释:如果分两组,可以把前三头分在一组,或把后三头分在一组;如果分三组,可以把中间两头分在一组,第一和最后一头奶牛自成一组;最后一种分法是把四头奶牛分在同一组里。
题解:
记录前缀理智和sum[i],l ~ r 可分成一组 当且仅当sum[r] >= sum[l-1];
令dp[i]表示以i作为某一段的结尾的分组方式。dp[n]就是要求的答案
dp[i]=∑dp[j] ……j<i且sum[j]<=sum[i];
<=sum[i]的dp[j]的和可以使用树状数组维护。
因此,先以sum[i]离散化,每次动态查询,动态修改
特别的 : dp[0] = 1,优先插入;
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 5e5 + 5, mod = 1e9 + 9;
typedef long long LL;
int n, k = -1, sum[N], b[N], c[N];
int lowbit(int x) { return x & -x; }
void add(int x, int k) {
for( ;x <= n + 5; x += lowbit(x)) (c[x] += k) %= mod;
}
int getsum(int x) {
int res = 0;
for( ; x ;x -= lowbit(x)) (res += c[x]) %= mod;
return res;
}
int main () {
cin >> n;
for(int i = 1;i <= n;i ++)
cin >> sum[i], sum[i] += sum[i-1], b[i] = sum[i];
sort(b + 1, b + n + 1);
for(int i = 0;i <= n;i ++)
sum[i] = lower_bound(b+1, b+n+1, sum[i]) - b + 2;
LL ans = 0;
add(sum[0], 1);
for(int i = 1;i <= n;i ++) {
ans = getsum(sum[i]);
add(sum[i], ans);
}
cout << ans << endl;
return 0;
}
作者:Paranoid丶离殇
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。