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