• bzoj 1044 [HAOI2008]木棍分割——前缀和优化dp


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044

    前缀和优化。

    但开成long long会T。(仔细一看不用开long long)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N=5e4+5,M=1005;
    const ll mod=10007;
    int n,m,a[N],pos[N];
    ll dp[N],l,r,lm,s[N],c[N],ans;
    void init()
    {
        while(l<=r)
        {
            ll mid=((l+r)>>1),sum=0;int cnt=1;
            for(int i=1;i<=n;i++)
            {
                if(sum+a[i]>mid)
                {
                    sum=a[i];cnt++;
                }
                else sum+=a[i];
            }
            if(cnt-1>m)l=mid+1;//分段,故cnt-1 
            else lm=mid,r=mid-1;
        }
        printf("%lld ",lm);//
    }
    void pre()
    {
        for(int i=1;i<=n;i++)
        {
            if(s[i]>lm)break;dp[i]=1;//dp:把前i个分成_段的方案数 
        }
        int now=0;
        for(int i=1;i<=n;i++)
            if(s[i]>lm)
            {
                while(s[i]-s[now]>lm)now++;
                pos[i]=now;//pos:本段首个的前一个 
            }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),l=max(l,(long long)a[i]),s[i]=s[i-1]+a[i];r=s[n];
        init();pre();
        while(m--)//已有分成1段的方案数,再来m次 
        {
            for(int i=1;i<=n;i++)c[i]=(c[i-1]+dp[i])%mod;//c:dp的前缀和 
            for(int i=1;i<=n;i++)dp[i]=((c[i-1]-c[max(0,pos[i]-1)])%mod+mod)%mod;//pos[i]-1:c[pos[i]]符合 
            (ans+=dp[n])%=mod;
        }
        printf("%lld",ans);
        return 0;
    }
    TLE的long long

    而且如果输出的 lm 改成 lm%mod ,就会WA。只开int就都好啦。(为什么?)

    那个处理pos的地方很好。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=5e4+5,mod=10007;
    int n,m,a[N],pos[N],dp[N],l,r,lm,s[N],c[N],ans;
    void init()
    {
        while(l<=r)
        {
            int mid=((l+r)>>1),sum=0,cnt=1;
            for(int i=1;i<=n;i++)
            {
                if(sum+a[i]>mid)
                {
                    sum=a[i];cnt++;
                }
                else sum+=a[i];
            }
            if(cnt-1>m)l=mid+1;
            else lm=mid,r=mid-1;
        }
        printf("%d ",lm);
    }
    void pre()
    {
        for(int i=1;i<=n;i++)
        {
            if(s[i]>lm)break;dp[i]=1;//dp:把前i个分成_段的方案数 
        }
        int now=0;
        for(int i=1;i<=n;i++)
            if(s[i]>lm)
            {
                while(s[i]-s[now]>lm)now++;
                pos[i]=now;//pos:本段首个的前一个 
            }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),l=max(l,a[i]),s[i]=s[i-1]+a[i];r=s[n];
        init();pre();
        while(m--)//已有分成1段的方案数,再来m次 
        {
            for(int i=1;i<=n;i++)c[i]=(c[i-1]+dp[i])%mod;//c:dp的前缀和 
            for(int i=1;i<=n;i++)dp[i]=((c[i-1]-c[max(0,pos[i]-1)])%mod+mod)%mod;//pos[i]-1:c[pos[i]]符合 
            (ans+=dp[n])%=mod;
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    Java web登录验证
    servlet总结
    Hadoop学习笔记(五)之HBASE
    C#学习笔记(二)
    C#学习笔记(一)
    Hadoop学习笔记(五)hdfs的四大机制和两大核心
    Hadoop学习笔记(三)Hadoop的hdfs的原理和运行机制
    Hadoop学习笔记(二)搭建伪分布式和集群模式的环境
    Linux系统常见命令
    python之路--day15--常用模块之logging模块
  • 原文地址:https://www.cnblogs.com/Narh/p/9243678.html
Copyright © 2020-2023  润新知