zoukankan      html  css  js  c++  java
  • 奶牛抗议

    奶牛抗议

    描述

    约翰家的N 头奶牛正在排队游行抗议。一些奶牛情绪激动,约翰测算下来,排在第i 位的奶牛的理智度为Ai,数字 
    可正可负。约翰希望奶牛在抗议时保持理性,为此,他打算将这条队伍分割成几个小组,每个抗议小组的理智度之 
    和必须大于或等于零。奶牛的队伍已经固定了前后顺序,所以不能交换它们的位置,所以分在一个小组里的奶牛必 
    须是连续位置的。除此之外,分组多少组,每组分多少奶牛,都没有限制。约翰想知道有多少种分组的方案,由于 
    答案可能很大,只要输出答案除以1000000009 的余数即可。 

    输入

    第一行:单个整数N,1 ≤ N ≤ 100000 
    第二行到第N + 1 行:第i + 1 行有一个整数Ai,10^5 ≤ Ai ≤ 10^5 

    输出

    单个整数:表示分组方案数模1000000009 的余数 

    样例

    输入

    4
    2
    3
    -3
    1

    输出

    4

    提示

    说明 
    解释:如果分两组,可以把前三头分在一组,或把后三头分在一组; 
    如果分三组,可以把中间两头分在一组,第一和最后一头奶牛自成一组;最后一种分法是把四头奶牛分在同一组里。

    思路:

    在做这道题之前,我们不妨先来想想这道题暴力怎么做。于是我们很容易得到一个简单的暴力转移方程:

    令f[i]表示到i的方案数,有f[i]=∑f[j],k=j+1∑i a[k]≥0
    写成前缀和的形式便是f[i]=∑f[j],sum[i]-sum[j]≥0,于是

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define mod 1000000009 
     4 using namespace std;
     5 ll n,sum[100005],ans,f[100005],a[100005];
     6 int main()
     7 {
     8     scanf("%lld",&n);
     9     for(ll i=1;i<=n;i++)
    10     {
    11         scanf("%lld",&a[i]);
    12         sum[i]=sum[i-1]+a[i];
    13     }
    14     f[0]=1;
    15     for(ll i=1;i<=n;i++)
    16         for(ll j=0;j<i;j++)
    17             if(sum[i]-sum[j]>=0)
    18                 f[i]=(f[i]+f[j])%mod;
    19     printf("%lld
    ",f[n]);
    20     return 0;
    21 }

    可是这是n^2,怎么优化?

    我们再来仔细看看这个代码,注意到这一句话:sum[i]-sum[j]>=0,我们将其转化一下是不是可以变成sum[i]>=sum[j]呢?

    这时候我们发现相当于求在i前面并且前缀和小于sum[i]的所有f[i]和,这就可以用一个树状数组优化了,在树状数组维护下标为sum[i],f[i]的前缀和。对于每个f[i]即为树状数组

    上sum[i]的前缀和。

    这里需要注意的是前缀和可能为负,而树状数组下标不能为负,所以我们要离散化一下。于是,上代码:

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define mod 1000000009
     4 #define lowbit(x) x&(-x)
     5 using namespace std;
     6 ll sum[1000001],n,f[1000001],b[1000001],num,a[1000001];
     7 struct data {
     8     ll v,id;
     9 } t[1000001];
    10 bool cmp(data x,data y) {
    11     if(x.v==y.v)
    12         return x.id<y.id;
    13     else
    14         return x.v<y.v;
    15 }
    16 void add(ll x,ll val) {
    17     while(x<=n+1) {
    18         sum[x]+=val;
    19         x+=lowbit(x);
    20     }
    21 }
    22 ll ask(ll x) {
    23     ll ans=0;
    24     while(x) {
    25         ans+=sum[x];
    26         x-=lowbit(x);
    27     }
    28     return ans;
    29 }
    30 int main() {
    31     scanf("%lld",&n);
    32     for(ll i=1; i<=n; i++) {
    33         scanf("%lld",&a[i]);
    34         f[i+1]=f[i]+a[i];
    35     }
    36     f[1]=0;
    37     for(ll i=1; i<=n+1; i++) {
    38         t[i].v=f[i];
    39         t[i].id=i;
    40     }
    41     sort(t+1,t+n+2,cmp);
    42     for(ll i=1; i<=n+1; i++)
    43         b[t[i].id]=i;//离散化
    44     add(b[1],1);
    45     for(ll i=2; i<=n+1; i++) {
    46         num=ask(b[i])%mod;
    47         add(b[i],num);
    48     }
    49     printf("%lld
    ",num%mod);
    50     return 0;
    51 }

    值得注意的是,我在这里把前0个数前缀和为零的情况也插入到了树状数组,所以注意一下小细节。

    如果有什么不对的地方欢迎各位巨佬指正。

    撒花~~~

  • 相关阅读:
    hdu 5387 Clock (模拟)
    CodeForces 300B Coach (并查集)
    hdu 3342 Legal or Not(拓扑排序)
    hdu 3853 LOOPS(概率DP)
    hdu 3076 ssworld VS DDD(概率dp)
    csu 1120 病毒(LICS 最长公共上升子序列)
    csu 1110 RMQ with Shifts (线段树单点更新)
    poj 1458 Common Subsequence(最大公共子序列)
    poj 2456 Aggressive cows (二分)
    HDU 1869 六度分离(floyd)
  • 原文地址:https://www.cnblogs.com/sbwll/p/13196215.html
Copyright © 2011-2022 走看看