Usaco 奶牛抗议(树状数组+DP+离散化)

题目链接:奶牛抗议
题解:用 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章