NOI 2009A 诗人小G

NOI 2009A 诗人小G

诗人小G

【问题描述】

小G是一个出色的诗人,经常作诗自娱自乐。但是,他一直被一件事情所困扰,那就是诗的排版问题。

一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中, 注意一行中可以放的句子数目是没有限制的。小G给每首诗定义了一个行标准长度(行的长度为一行中符号的总个数),他希望排版后每行的长度都和行标准长度相差不远。显然排版时,不应改变原有的句子顺序,并且小G不允许把一个句子分在两行或者更多的行内。在满足上面两个条件的情况下,小G对于排版中的每行定义了一个不协调度, 为这行的实际长度与行标准长度差值绝对值的P次方,而一个排版的不协调度为所有行不协调度的总和。

小G最近又作了几首诗,现在请你对这首诗进行排版,使得排版后的诗尽量协调(即不协调度尽量小),并把排版的结果告诉他。

【输入文件】

输入文件poet.in包含多组数据。

第一行包含一个整数T,表示诗的数量,接下来是T首诗,这里一首诗即为一组数据。每组数据的第一行包含三个由空格分隔的正整数NLP,其中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分

  1 //不要去洛谷上面提交,洛谷的这题数据有问题,去codeVs
  2 #include<cstdio>
  3 #include<cstring>
  4 #define ll long double
  5 //node[i]代表i,里面的l代表决策的作用起点,r代表决策的作用终点,p是决策的值
  6 struct node{int  l,r,p;}q[100100];
  7 #define MAX 1000000000000000000LL
  8 #define N 100100
  9 ll sum[N],f[N];
 10 int n,l,p,T;
 11 char ch[35];
 12 //求|y|^p的函数
 13 ll pow(ll y){
 14     if(y<0)y=-y;
 15     ll ans=1;
 16     for (int i=1;i<=p;i++) ans*=y;
 17     return ans;
 18 }
 19 //计算不协调度
 20 ll calc(int x,int y){
 21     return f[x]+pow(sum[y]-sum[x]+(y-x-1)-l);
 22 }
 23 //二分查找找决策转折点
 24 //node表示老决策点,x表示新决策点的值
 25 //这个函数就是在老的决策点的范围中寻找新的决策点的值
 26 int find(node t,int x){
 27     int l=t.l,r=t.r;
 28     while(l<=r){//当头小于等于尾,也就是还有数可以查找的时候
 29         //mid=(头+尾)/2
 30         int mid=(l+r)>>1;
 31         //小于的情况,也就是新的决策点更有,我们就要一直往前继续扩展新的决策点的起点,
 32         //直到老决策点比较好的时候
 33         if (calc(x,mid)<=calc(t.p,mid)) r=mid-1;
 34         //大于的情况,也就老决策点比较好的时候,我们往后搜索新决策点的作用域的起点
 35         else l=mid+1;
 36     }
 37     //返回头
 38     return l;
 39 }
 40
 41 void dp(){
 42     //用数组模拟栈,头置为1,尾置为0
 43     int head=1,tail=0;
 44     //将第一个决策入栈,决策1的起点为0,终点为n,决策的初始值置为0,因为初始决策就是0
 45     q[++tail]=(node){0,n,0};
 46     //求取f[i]
 47     for (int i=1;i<=n;i++){
 48         //如果栈头结点上的决策作用终点小于i,说明这个决策已经无法对i进行作用,所以我们要换新的决策
 49         //head<=tail栈的头小于等于尾,说明栈里面还有新的决策,那就换上新的决策
 50         //因为head++,所以此时头节点是指向新的决策
 51         if(q[head].r<i&&head<=tail) head++;
 52         //用新的可以作用i位置的决策来计算f[i]的值,这样计算出来的f[i]的值就是最优值
 53         f[i]=calc(q[head].p,i);
 54         //calc(i,n)表示通过值为i的决策去计算f[n]的值
 55         //calc(q[tail].p,n)表示通过旧决策q[tail].p去计算f[n]的值
 56         //calc(i,n)<=calc(q[tail].p,n)表示值为i的决策优于老决策,我们才进行下一步
 57         //不然,如果老决策更好,我们根部用不着换决策
 58
 59         //每一个被计算出来的f[i],都会使i成为新的决策,因为我有了f[i]的值,
 60         //所以我可以用f[i]的值帮助计算别的f[k](k>i),所以f[i]就是新的决策
 61
 62         /*
 63         比如说我们的样例1中,当i==3时,我们通过 q[head].p=2这个决策把f[3]算出来了
 64         比如说这里的n是4,如果calc(3,4)<=calc(2,4),那说明值为3的这个新决策更好,
 65         我们就要在决策2的作用区间里面找出决策3的作用区间
 66         */
 67
 68
 69         //如果新决策更好,找出新决策的作用范围
 70         //确定新决策点的终点
 71         if (calc(i,n)<=calc(q[tail].p,n)){
 72             //如果栈的头小于等于尾,head<=tail,说明栈里有元素
 73             //calc(q[tail].p,q[tail].l)表示用旧决策点决策值来决策旧决策点的起点
 74             //calc(i,q[tail].l)用新决策点来决策旧决策点的起点
 75             //如果后者小于前者,说明新决更好,那就要在更广阔的范围里面去寻找新决策点的决策范围
 76             //换句话说,就是当新决策点的作用范围覆盖了老决策点,我们要到比旧决策点更老点决策点里面寻找新决策点的作用方位
 77             while(head<=tail&&calc(q[tail].p,q[tail].l)>=calc(i,q[tail].l)) tail--;
 78             //head>tail说明栈已经为空了,就是说现在新决策点最好,所以把新决策点入栈
 79             if(head>tail)q[++tail]=(node){i,n,i};
 80             else{
 81                 //否则,我们就要去寻找新决策点的作用范围
 82                 //x返回新决策点范围的起点
 83                 int x=find(q[tail],i);
 84                 //旧决策点的尾部置为x-1
 85                 q[tail].r=x-1;
 86                 //将新决策点入栈
 87                 q[++tail]=(node){x,n,i};
 88             }
 89         }
 90     }
 91 }
 92
 93 int main(){
 94     scanf("%d",&T);
 95     while(T--){
 96         scanf("%d%d%d",&n,&l,&p);
 97         for (int i=1;i<=n;i++) scanf("%s",ch),sum[i]=sum[i-1]+strlen(ch);
 98         dp();
 99         if(f[n]>MAX)
100             puts("Too hard to arrange");
101         else
102             printf("%lld\n",(long long)f[n]);
103         puts("--------------------");
104     }
105     return 0;
106 }

代码对应的分析

时间: 2024-10-03 00:46:35

NOI 2009A 诗人小G的相关文章

BZOJ 1563 诗人小G(四边形优化)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1563 题意: 思路:设s[i]表示前i个句子的长度和,那么有转移方程: 有大牛证明这个满足四边形不等式,证明应该 比较复杂.在<1D/1D动态规划优化初步>这篇文章中,作者说实战中可以直接打表看看是不是满足,感觉还是比较实用的.不管那么多了,现在我们知道了满 足四边形不等式,也就是满足决策点单调.比如f[i]是用j更新的,那么i之后的点不可能用j之前的点更新,这就是决策单调性.那么我

BZOJ 1563 NOI2009 诗人小G 四边形不等式

题目大意:玩具装箱,然而指数变成了p(p≤10) 首先我们需要证明决策单调 由于数死早,还是戳这里吧 知道决策单调之后怎么办呢? 由于是1D1D,所以不能分治了 每个决策点能决策的区间一定是连续的一段 并且随着决策点的右移 这个区间也在不断右移 令g[j]表示决策点j能贡献的最左侧的位置 然后我们开一个栈来维护当前存在贡献的贡献点 那么显然stack[i]的贡献区间是[g[stack[i]],g[stack[i+1]]?1] 每新来一个点,首先在栈中二分找到最优决策点 然后将所有满足 f[sta

Bzoj 1563: [NOI2009]诗人小G(决策单调性优化)

原题面 带有详细证明的转这里 题意:每一个线段有一个长度,有一个标准长,现在要把这些线段按照顺序分行,每行的不和谐值等于标准长和该行线段总长的差的绝对值的p次方.现在要求最小的不和谐值之和. 开始的时候完全读错题了,以为p==2 for ever.真是太天真.后来看数据范围才发现.我真是面向数据编程? n^2的dp是一眼秒的.然后如果是p=2,那就是一个非常像玩具装箱的斜率优化dp.对于4.5的数据范围.可以想到用贪心优化dp.因为每一行的长度不会通过拼接线段(线段条数>=2)达到2*标准长,这

【BZOJ 1563】 [NOI2009]诗人小G

Description Input Output 对于每组数据,若最小的不协调度不超过1018,则第一行一个数表示不协调度若最小的不协调度超过1018,则输出"Too hard to arrange"(不包含引号).每个输出后面加"--------------------" Sample Input 4 4 9 3 brysj, hhrhl. yqqlm, gsycl. 4 9 2 brysj, hhrhl. yqqlm, gsycl. 1 1005 6 poet

题解——[NOI2009]诗人小G 决策单调性优化DP

第一次写这种二分来优化决策单调性的问题.... 调了好久,,,各种细节问题 显然有DP方程: f[i]=min(f[j] + qpow(abs(sum[i] - sum[j] - L - 1))); 其中f[i]代表到了第i个句子的最小答案 qpow用于处理^p sum为前缀和 (同时为了处理句子之间的空格问题,我们在统计前缀和的时候就默认在句子后面加一个空格, 然后在计算的时候,由于每一行只有最后一个不用加空格,直接减掉这个多加的空格即可获得正确长度) 首先我们可以打表发现是满足决策单调性的,

诗人小G(1D1D动态规划)

1D1D动态规划的转移式是长这样的: 对于形如f(i)=min(f(j)+w(j,i)) ,1<=i<=n-1f(i)=min(f(j)+w(j,i)),1<=i<=n?1的状态转移方程,记p[i]p[i]为令f[i]f[i]取到最小值的jj的值,即p[i]p[i]是f[i]f[i]的最优决策.若pp在[1,N][1,N]上单调不见,则称f具有决策单调性 其中 w[i,x]需要满足四边形不等式 emmm四边形不等式是什么呢? 对于定义域上的任意整数a,b,c,d,其中a\le b

ACM_小G的循环

小G的循环 Time Limit: 2000/1000ms (Java/Others) Problem Description: 一回生,二回熟,三回就腻,小G用for,while循环用得太多了,累觉不爱.于是自定义了一个循环,叫circle,形式如下: void circle(int n) { n--; if(n == 0) return; else circle(n); } 已知循环次数为该函数的调用次数,现在输入n(-2^31< =n< =2^31-1),求circle()的循环次数.

ACM_开挂的小G

开挂的小G Time Limit: 2000/1000ms (Java/Others) Problem Description: 小G寒假在家没网络,闲着没事干又看不下书,就玩起了单机游戏ACM_Game,不过,学计算机的怎么能老玩别人的游戏呢?自己做个?哦不,自己做的要是玩得不开心就会随便改代码啦,这样就没意思了.于是,小G费了点心思就给自己做了个ACM_Game辅助,让自己角色的分数快速增长.有多快呢?程序运行后,第一秒增加1,第2秒增加4,第3秒增加9... 第n秒就增加n^2.小G知道,

BZOJ4175 : 小G的电话本

用后缀树统计出出现了x次的本质不同的子串的个数,最后再乘以x,得到一个多项式. 这个多项式常数项为0,但是一次项不为0. 于是把整个多项式除以一次项,通过多项式求ln和多项式求exp求出它的幂. 最后再把除掉的项乘回来即可,时间复杂度$O(n\log n)$. #include<cstdio> #include<cstring> typedef long long ll; const int N=262144,K=17,inf=~0U>>2,S=27,M=200010,