zoukankan      html  css  js  c++  java
  • BZOJ1044 [HAOI2008]木棍分割 【二分+Dp】

    1044: [HAOI2008]木棍分割

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 4281  Solved: 1644
    [Submit][Status][Discuss]

    Description

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

    Input

      输入文件第一行有2个数n,m.接下来n行每行一个正整数Li,表示第i根木棍的长度.n<=50000,0<=m<=min(n-1,10
    00),1<=Li<=1000.

    Output

      输出有2个数, 第一个数是总长度最大的一段的长度最小值, 第二个数是有多少种砍的方法使得满足条件.

    Sample Input

    3 2
    1
    1
    10

    Sample Output

    10 2

    HINT

    两种砍的方法: (1)(1)(10)和(1 1)(10)



    显然我们可以二分算出第一问

    算出第一问后,我们就可以dp求方案数了

    设f[i][j]表示前i个木棒割j刀的方案数

    则f[i][j] = ∑f[k][j - 1]  【k < i 且 sum[i] - sum[k] <= mx】


    但这样做会爆

    首先我们可以滚动数组,空间不爆了

    其次我们会发现sum是递增的,也就是说k可以k + 1 ~ i - 1一定都可以,我们每次维护一次f的前缀和就可以加速了

    【注意:取模过程中涉及减法,最后答案输出时要取回正数】

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 50005,maxm = 1005,INF = 1000000000,P = 10007;
    inline int RD(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int n,m,f[2][maxn],A[maxn],sum[maxn],S[maxn],mx = 0,Sum = 0,ans = 0;
    bool check(int M){
    	if (mx > M) return false;
    	int cnt = 0,tot = 0;
    	for (int i = 1; i <= n; i++){
    		if (tot + A[i] > M) cnt++,tot = 0;
    		tot += A[i];
    		if (cnt > m) return false;
    	}
    	return true;
    }
    int main(){
    	n = RD(); m = RD();
    	REP(i,n) A[i] = RD(),sum[i] = sum[i - 1] + A[i],mx = max(mx,A[i]);
    	int l = 1,r = sum[n],mid;
    	while (l < r){
    		mid = l + r >> 1;
    		if (check(mid)) r = mid;
    		else l = mid + 1;
    	}
    	cout<<(mx = l)<<' ';
    	f[0][0] = 1;
    	for (int k = 0,p = 0; k <= m; k++){
    		S[0] = f[p][0];
    		REP(i,n) S[i] = (S[i - 1] + f[p][i]) % P;
    		p ^= 1; int pos = 0;
    		f[p][0] = 0;
    		for (int i = 1; i <= n; i++){
    			/*
    			for (int j = i - 1; j > 0; j--)
    				if (sum[i] - sum[j] <= mx)
    					f[p][i] = (f[p][i] + f[p ^ 1][j]) % P;
    				else break;*/
    			while (sum[i] - sum[pos] > mx) pos++;
    			f[p][i] = (S[i - 1] - (pos ? S[pos - 1] : 0)) % P;
    		}
    		ans = (ans + f[p][n]) % P;
    	}
    	cout<<(ans + P) % P<<endl;
    	return 0;
    }
    



  • 相关阅读:
    经典算法之七大排序
    Memcached在Asp.NET中的使用
    利用memcached构建高性能的Web应用程序(转)
    C# 反射机制
    数据库事务设置保存点
    C# 串口通信总结
    某投注网站的BUG
    浙江电信网上营业厅的一个BUG(有更新)
    解决DESCryptoServiceProvider加解密时弱密钥异常
    ASP.NET自定义控件开发示例(二)
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282780.html
Copyright © 2011-2022 走看看