题目链接:奶牛抗议
题解:用 dp[i] 表示前 i 头奶牛的分组方案,s[i] 表示前 i 头奶牛的理智度的和,那么就有转移 dp[i]=sum{ dp[j] } ( s[i]-s[j]>=0 且 i>j )。所以,把前缀和hash成树状数组下标,树状数组里存dp的值。时间复杂度 O(n*log n)。
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 100005
#define mod 1000000009
using namespace std;
struct node{
int v,id,hash;
bool operator < (const node& x)const{return v<x.v;}
}sum[N];
int n,a[N],tree[N],siz,j=1,ans;
bool cmp(node x,node y)
{
return x.id<y.id;
}
void add(int p,int d)
{
while (p<=siz)
{
tree[p]=(tree[p]+d)%mod;
p+=p&(-p);
}
}
int query(int p)
{
int res=0;
while (p>0)
{
res=(res+tree[p])%mod;
p-=p&(-p);
}
return res;
}
int main()
{
scanf("%d",&n);
sum[0].v=sum[0].id=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i].v=sum[i-1].v+a[i];
sum[i].id=i;
}
sort(sum,sum+n+1); //哈希
sum[0].hash=1;
for (int i=1;i<=n;i++)
{
if (sum[i].v!=sum[i-1].v) sum[i].hash=++j;
else sum[i].hash=j;
}
siz=j;
sort(sum,sum+n+1,cmp);
add(sum[0].hash,1);
for (int i=1;i<=n;i++) //按id排序保证了j<i,询问1到sum[i].hash的值就是询问sum[j]的和 (sum[j]<=sum[i]的dp[j]),非常神奇(⊙v⊙)
{
ans=query(sum[i].hash);
add(sum[i].hash,ans);
}
printf("%d\n",ans);
return 0;
}