http://www.lydsy.com/JudgeOnline/problem.php?id=1044

如果只求最大的最小,,直接二分就行了。。。可是要求方案。。

好神!

我竟然想不到!

因为我们得到的答案已经是最大的最小了,那么我们只要在每一次切割的时候,保证连续的每一段不超过ans即可,这就是方案数!

orz

所以设d[i,j]表示前j个切了i次,那么d[i,j]=sum{d[i-1, k], sum[j]-sum[k]<=ans}

这个二维可以变成一维,sum[j]-sum[k]的k具有单调性,所以我们维护一下k就行了。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mkpii make_pair<int, int>
#define pdi pair<double, int>
#define mkpdi make_pair<double, int>
#define pli pair<ll, int>
#define mkpli make_pair<ll, int>
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define printarr2(a, b, c) for1(_, 1, b) { for1(__, 1, c) cout << a[_][__]; cout << endl; }
#define printarr1(a, b) for1(_, 1, b) cout << a[_] << '\t'; cout << endl
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
inline const int max(const int &a, const int &b) { return a>b?a:b; }
inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=50005, MD=10007;
int n, a[N], sum[N], f[N], d[N], m, ans; bool check(int x) {
int tot=0, s=0;
for1(i, 1, n) {
if(a[i]>x) return false;
s+=a[i];
if(s>x) { s=a[i]; ++tot; }
if(tot>m) return false;
}
return true;
} int main() {
read(n); read(m);
int l=1, r=0;
for1(i, 1, n) read(a[i]), r+=a[i], sum[i]=sum[i-1]+a[i];
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
ans=r+1;
printf("%d", ans);
for1(i, 0, n) if(sum[i]<=ans) d[i]=1; else break;
for1(j, 1, m) {
int k=0;
f[0]=d[0];
for1(i, 1, n) f[i]=(f[i-1]+d[i])%MD;
for1(i, j+1, n) {
while(k<i && sum[i]-sum[k]>ans) ++k;
d[i]=(f[i-1]-f[k-1]+MD)%MD;
}
// for1(i, j+1, n) {
// for1(k, 0, i-1) if(sum[i]-sum[k]<=ans) d[i][j]=(d[i][j]+d[k][j-1]);
// }
}
printf(" %d\n", d[n]);
return 0;
}

  


Description

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

Input

输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍的长度.

Output

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

Sample Input

3 2
1
1
10

Sample Output

10 2

HINT

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

数据范围

n<=50000, 0<=m<=min(n-1,1000).

1<=Li<=1000.

Source

【BZOJ】1044: [HAOI2008]木棍分割(二分+dp)的更多相关文章

  1. BZOJ 1044: [HAOI2008]木棍分割(二分答案 + dp)

    第一问可以二分答案,然后贪心来判断. 第二问dp, dp[i][j] = sigma(dp[k][j - 1]) (1 <= k <i, sum[i] - sum[k] <= ans ...

  2. [BZOJ 1044] [HAOI2008] 木棍分割 【二分 + DP】

    题目链接:BZOJ 1044 第一问是一个十分显然的二分,贪心Check(),很容易就能求出最小的最大长度 Len . 第二问求方案总数,使用 DP 求解. 使用前缀和,令 Sum[i] 为前 i 根 ...

  3. BZOJ 1044: [HAOI2008]木棍分割

    Description 求 \(n\) 根木棍长度为 \(L\) ,分成 \(m\) 份,使最长长度最短,并求出方案数. Sol 二分+DP. 二分很简单啊,然后就是方案数的求法. 状态就是 \(f[ ...

  4. 【bzoj1044】[HAOI2008]木棍分割 二分+dp

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

  5. Luogu P2511 [HAOI2008]木棍分割 二分+DP

    思路:二分+DP 提交:3次 错因:二分写萎了,$cnt$记录段数但没有初始化成$1$,$m$切的次数没有$+1$ 思路: 先二分答案,不提: 然后有个很$naive$的$DP$: 设$f[i][j] ...

  6. 【BZOJ】1044: [HAOI2008]木棍分割 二分+区间DP

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1044 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, ...

  7. bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1044 [题意] n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数. ...

  8. bzoj 1044: [HAOI2008]木棍分割【二分+dp】

    对于第一问二分然后贪心判断即可 对于第二问,设f[i][j]为已经到j为止砍了i段,转移的话从$$ f[i][j]=\sigema f[k][j-1] (s[j]-s[k-1]<=ans) 这里 ...

  9. BZOJ 1044: [HAOI2008]木棍分割 DP 前缀和优化

    题目链接 咳咳咳,第一次没大看题解做DP 以前的我应该是这样的 哇咔咔,这tm咋做,不管了,先看个题解,再写代码 终于看懂了,卧槽咋写啊,算了还是抄吧 第一问类似于noip的那个跳房子,随便做 这里重 ...

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

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 前缀和优化. 但开成long long会T.(仔细一看不用开long long) #i ...

随机推荐

  1. 配置静态监听解决ORA-12514错误的案例

    今天做Linux下DG配置的时候,遇到一个现象.tnsname.ora文件配置都正常,tnsping也正常,监听也正常.可是仍然报ORA-12514错误: SQL> set lin 130 pa ...

  2. MyEclipse中出现Address already in use:JVM_Bind:8080

    今天在搭建环境,跑以前的一个项目时,出现了Address already in use 的错误,这显然是tomcat的端口号被占用了,我的机子上安装了appache和appache Tomcat: 我 ...

  3. Android日常开发总结

    全部Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效. 数据库表段字段常量和SQL逻辑分离,更清晰,建议使用 ...

  4. Nginx.conf简介

    vim /etc/nginx/nginx.conf #user nobody; worker_processes 1; #error_log logs/error.log; #error_log lo ...

  5. DBMS_METADATA中使用SESSION_TRANSFORM过滤不想获取的DDL

    我们一般使用dbms_metadata.get_ddl获取对象的ddl的时候,有时会获取一些其它额外的信息,比如当你想获取表的创建语句的时候,你会得到表的约束信息,这个信息可能是你不想要的,那么就能够 ...

  6. 转:sock_ev——linux平台socket事件框架(event dispatcher) .

    最近比较忙,好久没更新了:今天我们看一下事件的监听方式,在linux下面事件的监听方式有三种select.poll.epoll,性能上面epoll最高,如果仅是最多监听十多个描述符,用啥无所谓,如果是 ...

  7. Android系统示例分析之AccelerometerPlay

    程序界面: 创建 SimulationView , 实现接口 SensorEventListener , 实现接口中两个抽象方法 public void onSensorChanged(SensorE ...

  8. 统计重复字符串 如 eeefffkkkhjk 得到如下结果 3e3f3khjk;

    //统计重复字符串 如 eeefffkkkhjk 得到如下结果 3e3f3khjk; string zipStr = Console.ReadLine(); var charList = zipStr ...

  9. ExecuteScalar,ExecuteReader,ExecuteNonQuery区别

    ExecuteScalar is typically used when your query returns a single value. If it returns more, then the ...

  10. JEECG环境搭建(Maven版本)-总结Eclipse

    1.安装sql server 数据库: 解决办法: 控制面板→程序和功能→启用或关闭Windows功能 .Net Framework 3.5这一项未被完全选中(应为对勾,如果是方块也不可以) 选中该项 ...