zoukankan      html  css  js  c++  java
  • [haoi2008]木棍分割

    有n根木棍, 第i根木棍的长度为Li, n根木棍依次连结在一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍木棍的方法使得总长度最大的一段长度最小。

    第一问:明显的二分答案;

    第二问:状态转移方程很容易搞出来:f[i][j]=Σf[k][j-1]   sum[i]-sum[k]<=ans1 

    看起来是个O(n2m)的dp,但实际上,k的取值只可能是i之前连续的一段,用个q[j-1]表示计算f[i][j]时前面的合法的f[k][j-1]的和,然后类似单调队列的搞一搞即可;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<algorithm>
    #include<cstdlib>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    #include<cmath>
    using namespace std;
    #define FILE "1"
    #define LL long long 
    #define up(i,j,n) for(int i=j;i<=n;i++)
    #define pii pair<int,int>
    #define piii pair<int,pair<int,int> >
    template<typename T> inline bool chkmin(T &a,T b){return a>b?a=b,true:false;}
    template<typename T> inline bool chkmax(T &a,T b){return a<b?a=b,true:false;}
    namespace IO{
        char *fs,*ft,buf[1<<15];
        inline char gc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
        inline int read(){
            int x=0,ch=gc();bool f=0;
            while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=gc();}
            while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=gc();}
            return f?-x:x;
        }
    }using namespace IO;
    namespace OI{
        const int maxn(51000),inf(100000000),mod(10007);
        int n,m;
        int a[maxn],sum[maxn];
        bool check(int mid){
            int sum=0,ans=1;
            for(int i=1;i<=n;i++){
                sum+=a[i];
                if(sum>mid)ans++,sum=a[i];
            }
            if(ans>m)return 0;
            else return 1;
        }
        int q[maxn],head;
        short int f[maxn][1010];
        void slove(){
            n=read(),m=read();m++;
            int maxx=0;
            up(i,1,n)a[i]=read(),chkmax(maxx,a[i]);
            int left=maxx,right=inf,mid,ans;
            while(left<=right){
                mid=(left+right)>>1;
                if(check(mid))right=mid-1,ans=mid;
                else left=mid+1;
            }
            up(i,1,n)sum[i]=sum[i-1]+a[i];
            head=0;
            f[0][0]=1;
            q[0]=1;
            for(int i=1;i<=n;i++){
                while(sum[i]-sum[head]>ans){
                    for(int j=1;j<=m&&j<=i;j++)q[j-1]=(q[j-1]-f[head][j-1]+mod)%mod;
                    head++;
                }
                for(int j=1;j<=m&&j<=i;j++)f[i][j]=q[j-1];
                for(int j=min(i,m);j>=1;j--)q[j]=(q[j]+q[j-1])%mod;
            }
            int y=0;
            for(int i=1;i<=m;i++)y=(y+f[n][i])%mod;
            printf("%d %d
    ",ans,y);
        }
    }
    int main(){
        using namespace OI;
        slove();
        return 0;
    }
  • 相关阅读:
    【简】题解 AWSL090429 【市场】
    【简】题解 AWSL090429 【噪音】
    差分约束
    凸包模板
    杂模板
    后缀数组刷题
    Trie刷题
    字符串模板
    网络流建模专题
    组合数模板
  • 原文地址:https://www.cnblogs.com/chadinblog/p/5998488.html
Copyright © 2011-2022 走看看