NOI 2009A 诗人小G
NOI 2009A 诗人小G
诗人小G
【问题描述】
小G是一个出色的诗人,经常作诗自娱自乐。但是,他一直被一件事情所困扰,那就是诗的排版问题。
一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中, 注意一行中可以放的句子数目是没有限制的。小G给每首诗定义了一个行标准长度(行的长度为一行中符号的总个数),他希望排版后每行的长度都和行标准长度相差不远。显然排版时,不应改变原有的句子顺序,并且小G不允许把一个句子分在两行或者更多的行内。在满足上面两个条件的情况下,小G对于排版中的每行定义了一个不协调度, 为这行的实际长度与行标准长度差值绝对值的P次方,而一个排版的不协调度为所有行不协调度的总和。
小G最近又作了几首诗,现在请你对这首诗进行排版,使得排版后的诗尽量协调(即不协调度尽量小),并把排版的结果告诉他。
【输入文件】
输入文件poet.in包含多组数据。
第一行包含一个整数T,表示诗的数量,接下来是T首诗,这里一首诗即为一组数据。每组数据的第一行包含三个由空格分隔的正整数N、L、P,其中N表示这首诗句子的数目,L表示这首诗的行标准长度,P的含义见问题描述。从第2行开始,每行为一个句子,句子由英文字母、数字、标点符号等符号组成(ASCII码33~127, 但不包含 ‘-’)。
【输出文件】
输出文件为poet.out。
对于每组数据,若最小的不协调度不超过1018,则第一行一个数表示不协调度,接下来若干行,表示你排版之后的诗。注意:在同一行的相邻两个句子之间需要用一个空格分开。如果有多个可行解,它们的不协调度都是最小值,则输出任意一个解均可。若最小的不协调度超过1018,则输出"Too hard to arrange"(不包含引号)。每组数据结束后输出"--------------------"(不包括引号),共20个"-","-"的ASCII码为45,请勿输出多余的空行或者空格。
【输入样例】
4
4 9 3
brysj,
hhrhl.
yqqlm,
gsycl.
4 9 2
brysj,
hhrhl.
yqqlm,
gsycl.
1 1005 6
poet
1 1004 6
poet
【输出样例】
108
brysj,
hhrhl.
yqqlm,
gsycl.
--------------------
32
brysj, hhrhl.
yqqlm, gsycl.
--------------------
Too hard to arrange
--------------------
1000000000000000000
poet
--------------------
【样例说明】
前两组输入数据中每行的实际长度均为6,后两组输入数据每行的实际长度均为4。一个排版方案中每行相邻两个句子之间的空格也算在这行的长度中(可参见样例中第二组数据)。每行末尾没有空格。
【评分方法】
本题设有部分分,当你的程序对于该测试点内每组数据计算得出的不协调度最小值都正确时,能得到本测试点70%的分数。在此情况下,若每组数据的排版方案都合法并且得出的不协调度都与输出的相等,则能得到本测试点剩下30%的分数。注意,输出格式错误可能会导致本测试点不得分。
【数据规模和约定】
总共10个测试点,数据范围满足:
测试点 |
T |
N |
L |
P |
1 |
≤10 |
≤18 |
≤100 |
≤5 |
2 |
≤10 |
≤2000 |
≤60000 |
≤10 |
3 |
≤10 |
≤2000 |
≤60000 |
≤10 |
4 |
≤5 |
≤100000 |
≤200 |
≤10 |
5 |
≤5 |
≤100000 |
≤200 |
≤10 |
6 |
≤5 |
≤100000 |
≤3000000 |
2 |
7 |
≤5 |
≤100000 |
≤3000000 |
2 |
8 |
≤5 |
≤100000 |
≤3000000 |
≤10 |
9 |
≤5 |
≤100000 |
≤3000000 |
≤10 |
10 |
≤5 |
≤100000 |
≤3000000 |
≤10 |
所有测试点中均满足句子长度不超过30。
直接dp,30分做法详细分析:
状态转移方程:
f[i] = min(f[j] + |s[i] - s[j] + i - j - 1 - L| ^ p) (0<=j<i)
f(i)表示将前i行诗放入整行的最小不协调度
s表示前缀和
可以使用1D1D动态规划,100分
//不要去洛谷上面提交,洛谷的这题数据有问题,去codeVs
#include<cstdio>
#include<cstring>
#define ll long double
//node[i]代表i,里面的l代表决策的作用起点,r代表决策的作用终点,p是决策的值
struct node{int l,r,p;}q[];
#define MAX 1000000000000000000LL
#define N 100100
ll sum[N],f[N];
int n,l,p,T;
char ch[];
//求|y|^p的函数
ll pow(ll y){
if(y<)y=-y;
ll ans=;
for (int i=;i<=p;i++) ans*=y;
return ans;
}
//计算不协调度
ll calc(int x,int y){
return f[x]+pow(sum[y]-sum[x]+(y-x-)-l);
}
//二分查找找决策转折点
//node表示老决策点,x表示新决策点的值
//这个函数就是在老的决策点的范围中寻找新的决策点的值
int find(node t,int x){
int l=t.l,r=t.r;
while(l<=r){//当头小于等于尾,也就是还有数可以查找的时候
//mid=(头+尾)/2
int mid=(l+r)>>;
//小于的情况,也就是新的决策点更有,我们就要一直往前继续扩展新的决策点的起点,
//直到老决策点比较好的时候
if (calc(x,mid)<=calc(t.p,mid)) r=mid-;
//大于的情况,也就老决策点比较好的时候,我们往后搜索新决策点的作用域的起点
else l=mid+;
}
//返回头
return l;
} void dp(){
//用数组模拟栈,头置为1,尾置为0
int head=,tail=;
//将第一个决策入栈,决策1的起点为0,终点为n,决策的初始值置为0,因为初始决策就是0
q[++tail]=(node){,n,};
//求取f[i]
for (int i=;i<=n;i++){
//如果栈头结点上的决策作用终点小于i,说明这个决策已经无法对i进行作用,所以我们要换新的决策
//head<=tail栈的头小于等于尾,说明栈里面还有新的决策,那就换上新的决策
//因为head++,所以此时头节点是指向新的决策
if(q[head].r<i&&head<=tail) head++;
//用新的可以作用i位置的决策来计算f[i]的值,这样计算出来的f[i]的值就是最优值
f[i]=calc(q[head].p,i);
//calc(i,n)表示通过值为i的决策去计算f[n]的值
//calc(q[tail].p,n)表示通过旧决策q[tail].p去计算f[n]的值
//calc(i,n)<=calc(q[tail].p,n)表示值为i的决策优于老决策,我们才进行下一步
//不然,如果老决策更好,我们根部用不着换决策 //每一个被计算出来的f[i],都会使i成为新的决策,因为我有了f[i]的值,
//所以我可以用f[i]的值帮助计算别的f[k](k>i),所以f[i]就是新的决策 /*
比如说我们的样例1中,当i==3时,我们通过 q[head].p=2这个决策把f[3]算出来了
比如说这里的n是4,如果calc(3,4)<=calc(2,4),那说明值为3的这个新决策更好,
我们就要在决策2的作用区间里面找出决策3的作用区间
*/ //如果新决策更好,找出新决策的作用范围
//确定新决策点的终点
if (calc(i,n)<=calc(q[tail].p,n)){
//如果栈的头小于等于尾,head<=tail,说明栈里有元素
//calc(q[tail].p,q[tail].l)表示用旧决策点决策值来决策旧决策点的起点
//calc(i,q[tail].l)用新决策点来决策旧决策点的起点
//如果后者小于前者,说明新决更好,那就要在更广阔的范围里面去寻找新决策点的决策范围
//换句话说,就是当新决策点的作用范围覆盖了老决策点,我们要到比旧决策点更老点决策点里面寻找新决策点的作用方位
while(head<=tail&&calc(q[tail].p,q[tail].l)>=calc(i,q[tail].l)) tail--;
//head>tail说明栈已经为空了,就是说现在新决策点最好,所以把新决策点入栈
if(head>tail)q[++tail]=(node){i,n,i};
else{
//否则,我们就要去寻找新决策点的作用范围
//x返回新决策点范围的起点
int x=find(q[tail],i);
//旧决策点的尾部置为x-1
q[tail].r=x-;
//将新决策点入栈
q[++tail]=(node){x,n,i};
}
}
}
} int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&l,&p);
for (int i=;i<=n;i++) scanf("%s",ch),sum[i]=sum[i-]+strlen(ch);
dp();
if(f[n]>MAX)
puts("Too hard to arrange");
else
printf("%lld\n",(long long)f[n]);
puts("--------------------");
}
return ;
}
代码对应的分析
NOI 2009A 诗人小G的更多相关文章
- [BZOJ 1563] [NOI 2009] 诗人小G(决策单调性)
[BZOJ 1563] [NOI 2009] 诗人小G(决策单调性) 题面 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中,注意一行中可以放的句子数目是没有限制的.小 G ...
- NOI 2009 诗人小G
题目描述 Description 小G是一个出色的诗人,经常作诗自娱自乐.但是,他一直被一件事情所困扰,那就是诗的排版问题. 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行 ...
- 解题:NOI 2009 诗人小G
题面 今天考试考了,于是开始糊学决策单调性DP 这是一个完全不会优化DP的人 决策单调性DP的一种优化方法是用单调队列优化 存下{左端点l,右端点r,最优决策点p}的三元组,按照单调队列的通常操作来说 ...
- C++之路进阶——codevs2933(诗人小G)
2933 诗人小G 2009年NOI全国竞赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description 小G是一个出色的诗人 ...
- 【Luogu1912】【NOI2009】诗人小G(动态规划)
[Luogu1912][NOI2009]诗人小G(动态规划) 题面 洛谷 题解 原来\(NOI\)这么多神仙题... 考虑一个极其明显的\(dp\) 设\(f[i]\)表示前\(i\)个句子产生的最小 ...
- LG1912 [NOI2009]诗人小G
题意 题目描述 小G是一个出色的诗人,经常作诗自娱自乐.但是,他一直被一件事情所困扰,那就是诗的排版问题. 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中,注意一行中可以 ...
- bzoj1563: [NOI2009]诗人小G 决策单调性(1D1D)
目录 题目链接 题解 代码 题目链接 bzoj1563: [NOI2009]诗人小G 题解 \(n^2\) 的dp长这样 \(f_i = min(f_j + (sum_i - sum_j - 1 - ...
- 1563: [NOI2009]诗人小G
1563: [NOI2009]诗人小G https://lydsy.com/JudgeOnline/problem.php?id=1563 分析: 直接转移f[i]=f[j]+cost(i,j),co ...
- BZOJ1563/洛谷P1912 诗人小G 【四边形不等式优化dp】
题目链接 洛谷P1912[原题,需输出方案] BZOJ1563[无SPJ,只需输出结果] 题解 四边形不等式 什么是四边形不等式? 一个定义域在整数上的函数\(val(i,j)\),满足对\(\for ...
随机推荐
- eclipse整合maven下载jar包速度慢问题解决
引用:http://blog.csdn.net/u010154380/article/details/70339538 开发过程中在pom.xml中添加pom的时候,默认是需要从中央仓库中下载,但是下 ...
- html5——web字体
基本介绍 1.自定义网页特殊字体,无需考虑用户电脑上是否安装了此特殊字体,从此把特殊字体处理成图片的时代便成为了过去. 2.支持程度比较好,甚至IE低版本浏览器也能支持. 3.web字体的大小鉴定是字 ...
- Codeforces_The least round way
B. The least round way time limit per test 2 seconds memory limit per test 64 megabytes input standa ...
- HDU_1285_拓扑排序(优先队列)
确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- Python random模块&string模块 day3
一.random模块的使用: Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. 1.常用函数: (1)random.random() 用于生成一个0到1 ...
- ES6学习历程(字符串的扩展)
字符串的扩展 在看这一节的时候前半部分写的都是关于unicode的内容,我个人感觉这部分在实际的开发中用的很少,所以不打算在做记录,等届时用到再有针对性的看,所以就将在ES6里面关于字符串操作的一些新 ...
- grep,cut,wc,sort,diff,uniq,patch命令
文本处理工具: Linux上文本处理三剑客: grep,egrep,fgrep: 文本过滤工具(模式: pattern)工具; grep:基本正则表达式,-E,-F egrep:扩展正则表达式,-G, ...
- 升级 Linux 内核版本(编译源代码)
升级内核版本(自己编译源码) 从 linux 官网 https://www.kernel.org/ 下载内核源码 解压 tar -xvf linux-4.16.8.tar.xz cd linux-4. ...
- Python 输出带颜色的文字方法
输出文字带颜色 书写格式,和相关说明如下: #格式: 设置颜色: \033[显示方式;前景色;背景色m \033[0m 方法: 字体色 背景色 颜色 -------------------- ...
- Redis 原子操作INCR
The content below come from http://try.redis.io/ There is something special about INCR. Why do we pr ...