1. 程式人生 > 實用技巧 >LG P2344 [USACO11FEB]Generic Cow Protests G

LG P2344 [USACO11FEB]Generic Cow Protests G

Description

Farmer John 的 $N$頭奶牛($1 \leq N \leq 10^5$)排成一列,正在進行一場抗議活動。第 $i$頭奶牛的理智度為 $a_i$$-10^4 \leq a_i \leq 10^4$)。

FJ 希望奶牛在抗議時保持理性,為此,他打算將所有的奶牛隔離成若干個小組,每個小組內的奶牛的理智度總和都要不小於零。

由於奶牛是按直線排列的,所以一個小組內的奶牛位置必須是連續的。請幫助 FJ 計算一下,滿足條件的分組方案有多少種。

Solution

對於$n^2$做法,有轉移方程

$$dp_i=\sum dp_j, \sum_{k=j+1}^i a_k \geq 0$$

$$dp_i=\sum dp_j, sum_i-sum_j \geq 0$$

考慮優化

對於上面的轉移方程,$i$能從$j$轉移來當且僅當

  • $j < i$
  • $sum_j \leq sum_i$

可以用樹狀陣列做二維偏序

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
long long n,sum[100005],tot,bit[100005],ans,a[100005];
const long long mod=1e9+9
; map<long long,long long>mp; inline long long read() { long long f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch
=getchar(); } return f*w; } long long lowbit(long long x) { return x&-x; } long long add(long long p,long long v) { while(p<=n) { bit[p]+=v; p+=lowbit(p); } } long long query(long long p) { long long ret=0; while(p) { ret+=bit[p]; p-=lowbit(p); } return ret; } int main() { n=read(); for(long long i=1;i<=n;i++) { a[i]=sum[i]=sum[i-1]+read(); } sort(sum,sum+n+1); tot=unique(sum,sum+n+1)-sum-1; for(long long i=0;i<=tot;i++) { mp[sum[i]]=i+1; } add(mp[0],1); for(long long i=1;i<n;i++) { ans=query(mp[a[i]])%mod; add(mp[a[i]],ans); } printf("%lld\n",query(mp[a[n]])%mod); return 0; }
[USACO11FEB]Generic Cow Protests G