• [Usaco2011 Feb]Generic Cow Protests奶牛抗议


    题目

    Description

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

    Input

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

    Output

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

    Sample Input

    4
    2
    3
    -3
    1

    Sample Output

    4

    Hint

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


    思路:

    如果不知道怎么求a前面小于a的个数

    https://www.cnblogs.com/wzx-RS-STHN/p/13193271.html

    暴力

    首先我们先把这一题的dp思路想清;

    dp[i]代表1-i的分组方案数;s[i]代表1-i的和;

    如果j-i区间的和大于等于 0;dp[i]+=dp[j];

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll a=0,ha=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') ha=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*ha;
    }
    const ll N=5*1e5;
    const ll mod=1000000009;
    ll s[N],ans,n,a[N],dp[N];
    int main()
    {
        n=read();
        for(ll i=1;i<=n;i++)
        {
            a[i]=read();
            s[i]=s[i-1]+a[i];
        }
        dp[0]=1;
        for(ll i=1;i<=n;i++)
        for(ll j=0;j<i;j++)
        {
            if(s[i]>=s[j])//相当if(s[i]-s[j]>=0) 也就是看这一段和是否>=0 
                dp[i]=(dp[i]+dp[j])%mod;
        }
        printf("%lld
    ",dp[n]);
    }

    正解

    那么怎么优化呢?树状数组!!!

    转移方程

        for(ll j=0;j<i;j++)
        {
            if(s[i]>=s[j])//相当if(s[i]-s[j]>=0) 也就是看这一段和是否>=0 
                dp[i]=(dp[i]+dp[j])%mod;
        }

    容易想到,这一段代码其实相当于求,s[i]前面比s[i]小&&等于s[i]的s[j]有多少个;dp[i]+=dp[j];

        ll x=findout(b[i]);//找出前面有多少数比b[i]小,并把那些位置上的方案数加上; 
            ans=x%mod;
            insert(b[i],ans);//将ans加入树状数组相当于暴力代码的记录dp[i] 

    b[i]是s[i]的离散化;

    因为我们求的是dp[i]+=dp[j],也就是求最后的答案,那么每一次直接插入dp[i]的答案就好了;

    通过树状数组优化转移方程就ok了;

    需要注意的问题是要s[1]=0,因为s[i]-s[1]相当于1-i的前缀和;

    如果s[1]不从0开始,那么会少统计1-i的前缀和;

    代码:

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll a=0,ha=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') ha=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*ha;
    }
    const ll mod=1000000009;
    ll n,m,sum[1000010];
    ll b[1000010],a1[1000010],s[1000010];
    struct oh
    {
        ll v,num;
    }a[1000010];
    inline ll lowbit(ll x)//树状数组基本操作 
    {
        return x&(-x);
    }
    inline void insert(ll x,ll y)
    {
        while(x<=n+1)
        {
            sum[x]+=y;
            x+=lowbit(x);
        }
    }
    inline ll findout(ll x)
    {
        ll ans=0;
        while(x)
        {
            ans+=sum[x];
            x-=lowbit(x);
        }
        return ans;
    }
    inline ll cmp(oh a,oh b)
    {
        if(a.v==b.v)
            return a.num<b.num;
        else
            return a.v<b.v;
    }
    int main()
    {
        n=read();
        for(ll i=1;i<=n;i++)
        {
            a1[i]=read();
            s[i+1]=s[i]+a1[i];//记录前缀和 
        }
        s[1]=0;
        for(ll i=1;i<=n+1;i++)
        {
            a[i].v=s[i];
            a[i].num=i;
        }//离散化 
        sort(a+1,a+n+2,cmp);
        for(ll i=1;i<=n+1;i++)
            b[a[i].num]=i;
        //代码修改艰难痕迹 
    //    cout<<endl;
    //    for(ll i=1;i<=n+1;i++)
    //        cout<<b[i]<<endl;
        insert(b[1],1);
        ll ans=0;
        for(ll i=2;i<=n+1;i++)
        {
            ll x=findout(b[i]);//找出前面有多少数比b[i]小,并把那些位置上的方案数加上; 
            ans=x%mod;
            insert(b[i],ans);//将ans加入树状数组相当于暴力代码的记录dp[i] 
        }
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    《区块链100问》第51集:区块链资产有匿名性
    《区块链100问》第52集:区块链资产能去中心化记账
    《区块链100问》第53集:区块链资产不可复制
    day 5 模块导入、常用模块os shutil sys commands subprocess hashlib json pickle zipfile traceback random datetime pathlib
    apache中配置php支持模块模式、cgi模式和fastcgi模式的实验
    day3--集合、文件操作、字符编码与转换、函数(递归,lambda,filter,map)、字典排序
    练习题目 :if for while else range、xrange、zip
    解决mySQL占用内存超大问题
    my.cnf重要配置参数说明
    chattr与lsattr命令详解
  • 原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/13194555.html
Copyright © 2020-2023  润新知