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

    Description

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

    Solution

    第一问是一个显然的二分贪心搞定。
    第二问是这道题的核心部分。容易想到一个简单dp,(f[i][j])表示当前考虑到第(i)个点, 截取了(j)个木棍的方案树,得(f[i][j] = Sigma{f[k][j - 1]} (k < i, sum[i] - sum[k] leqslant ans1))。空间时间都会炸。空间很好优化,滚动一下就好了。时间略微难一点,但是还是好想,因为前缀和是单调的,所以用单调队列可以优化。如果(sum[i]-sum[k]<=ans),就把计算后的值塞到队列里去。

    #include<map>
    #include<queue>
    #include<bitset>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define drp(i, a, b) for (int i = a; i >= b; i--)
    #define fech(i, x) for(int i = 0; i < x.size(); i++)
    #define N 50001
    #define ha 10007
    
    inline int read() {
    	int x = 0, flag = 1; char ch = getchar();
    	while (ch > '9' || ch < '0') { if (ch == '-') flag = -1; ch = getchar(); }
    	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    	return x * flag;
    }
    inline void write(int x) { if (x >= 10) write(x / 10); putchar(x % 10 + '0'); }
    
    int n, m;
    int a[N], sum[N];
    int f[2][N], q[N];
    int ans1, ans2;
    
    bool check(int x) {
    	int now = 0, t = 1;
    	rep(i, 1, n)
    		if (now + a[i] <= x) now += a[i];
    		else {
    			if (a[i] > x || t >= m) return 0;
    			t++; now = a[i];
    		}
    	return 1;
    }
    
    int binary(int l, int r) {
    	if (l == r) return l;
    	int mid = l + r >> 1;
    	if (check(mid)) return binary(l, mid);
    	return binary(mid + 1, r);
    }
    
    int main()
    {
    	scanf("%ld%ld", &n, &m); m++;
    	rep(i, 1, n) a[i] = read(), sum[i] = sum[i - 1] + a[i];
    	ans1 = binary(0, sum[n]);
    	printf("%ld ", ans1);
    	rep(i, 1 ,n) if (sum[i] <= ans1) f[1][i] = 1; else break;
    	int now = 1;
    	rep(j, 2, m) {
    		now ^= 1;
    		memset(f[now], 0, sizeof f[now]);
    		memset(q, 0, sizeof q);
    		int k = n + 1;
    		drp(i, n, 2) {
    			if (i > k) f[now][i] += (q[k] - q[i]) % ha; else k = i;
    			while (k > 1 && sum[i] - sum[k - 1] <= ans1) {
    				k--;
    				(f[now][i] += f[now ^ 1][k]) %= ha;
    				q[k] = (q[k + 1] + f[now ^ 1][k]) % ha;
    			}
    		}
    		(ans2 += f[now][n]) %= ha;
    	}
    	printf("%ld", ans2);
    	return 0;
    }
    
  • 相关阅读:
    【Android
    【Android
    GeoIP的使用
    从30岁到35岁:为你的生命多积累一些厚度[转]
    editplus运行php 配置
    zend studio10 创建重复project from remote server
    《淘宝技术这10年》
    顶级程序员的10条最佳实践
    PHP_EOL 换行符
    尝试用Gearman实现分布式处理(PHP)[转]
  • 原文地址:https://www.cnblogs.com/aziint/p/8416139.html
Copyright © 2011-2022 走看看