題目描述 Description
小G是一個出色的詩人,經常作詩自娛自樂。但是,他一直被一件事情所困擾,那就是詩的排版問題。
一首詩包含了若干個句子,對於一些連續的短句,可以將它們用空格隔開並放在一行中,注意一行中可以放的句子數目是沒有限制的。小G給每首詩定義了一個行標準長度(行的長度為一行中符號的總個數),他希望排版後每行的長度都和行標準長度相差不遠。顯然排版時,不應改變原有的句子順序,並且小G不允許把一個句子分在兩行或者更多的行內。在滿足上面兩個條件的情況下,小G對於排版中的每行定義了一個不協調度, 為這行的實際長度與行標準長度差值絕對值的P次方,而一個排版的不協調度為所有行不協調度的總和。
小G最近又作了幾首詩,現在請你對這首詩進行排版,使得排版後的詩盡量協調(即不協調度盡量小),並把排版的結果告訴他。 輸入描述 Input Description
本題中包含多組測試資料。
輸入檔案中的第一行為一個整數T,表示詩的數量。
接下來為T首詩,這裡一首詩即為一組測試資料。每組測試資料中的第一行為三個由空格分隔的正整數N,L,P,其中:N表示這首詩句子的數目,L表示這首詩的行標準長度,P的含義見問題描述。
從第二行開始,每行為一個句子,句子由英文字母、數字、標點符號等符號組成(ASCII碼33~127,但不包含’-‘)。 輸出描述 Output Description
對於每組測試資料,若最小的不協調度不超過10^18,則第一行為一個數,表示不協調度。接下來若干行,表示你排版之後的詩。注意:在同一行的相鄰兩個句子之間需要用一個空格分開。
如果有多個可行解,它們的不協調度都是最小值,則輸出任意一個解均可。若最小的不協調度超過10^18,則輸出“Too hard to arrange”(不含引號)。每組測試資料結束後輸出“——————–”(不含引號),共20個“-”,“-”的ASCII碼為45,請勿輸出多餘的空行或者空格。
由於缺少special judge,因此在這裡只要求輸出最小的不協調度。格式不變,依然以”-“分割。 範例輸入 Sample Input
4
4 9 3
brysj,
hhrhl.
yqqlm,
gsycl.
4 9 2
brysj,
hhrhl.
yqqlm,
gsycl.
1 1005 6
poet
1 1004 6
poet 範例輸出 Sample Output
108
−−−−−−−−−−−−−−−−−−−− --------------------
32
−−−−−−−−−−−−−−−−−−−− --------------------
Too hard to arrange
−−−−−−−−−−−−−−−−−−−− --------------------
1000000000000000000
−−−−−−−−−−−−−−−−−−−− -------------------- 資料範圍及提示 Data Size & Hint
【範例說明】
前兩組輸入資料中每行的實際長度均為6,後兩組輸入資料每行的實際長度均為4。一個排版方案中每行相鄰兩個句子之間的空格也算在這行的長度中(可參見範例中第二組資料)。每行末尾沒有空格。
所有測試點中均滿足句子長度不超過30。 題解
30分演算法:
1,2,3組資料:樸素動態規劃,轉移方程:
f[i]=min(f[j]+|s[i]−s[j]+i−j−1−L|p)。 f[i] = min(f[j] + |s[i] - s[j] + i - j - 1 - L| ^ p)。
100分演算法:
既然直接dp只有30分,那麼我們該想如何進行最佳化。
我們可以看出這是一個1D1D動態規劃,那麼決策區間就是連續的段落,於是我們維護一個上凸殼,每次更新的時候用二分就好了,注意也要用隊列來最佳化。
注意資料比較大,用long double 算完轉long long輸出。 代碼
#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>typedef long double ll;#define inf 9000000000000000000#define MAX 1000000000000000000LLusing namespace std;int t,n,l,p,top;ll sum[100005],f[100005],from[100005];char ch[100005][35];struct nod{ int l,r,p; nod(){} nod(int a,int b,int c):l(a),r(b),p(c){}}q[100005];inline ll read() { ll x=0; char c=getchar(); while(c<'0' || c>'9') c=getchar(); while(c<='9' && c>='0'){x=x*10+c-'0';c=getchar();} return x; }inline ll pow(ll x) { if(x<0) x=-x; ll ans=1; for(int i=1;i<=p;i++) ans*=x; return ans;}inline ll cal(int j,int i) { return f[j]+pow(sum[i]-sum[j]+(i-j-1)-l);}int find(nod a,int b) { int l=a.l,r=a.r; while(l<=r) { int mid=l+r>>1; if(cal(a.p,mid)<cal(b,mid)) l=mid+1; else r=mid-1; } return l;}void dp() { int hd=1,tl=0; q[++tl]=nod(0,n,0); for(int i=1;i<=n;i++) { if(hd<=tl && i>q[hd].r) hd++; f[i]=cal(q[hd].p,i);from[i]=q[hd].p; if(hd>tl || cal(i,n)<=cal(q[tl].p,n)) { while(hd<=tl && cal(i,q[tl].l)<=cal(q[tl].p,q[tl].l)) tl--; if(hd>tl) q[++tl]=nod(i,n,i); else { int t=find(q[tl],i); q[tl].r=t-1; q[++tl]=nod(t,n,i); } } }}int main() { t=read(); while(t--) { n=read(),l=read(),p=read(); for(int i=1;i<=n;i++) scanf("%s",ch[i]); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+strlen(ch[i]); dp(); if(f[n]>MAX) printf("Too hard to arrange\n"); else printf("%lld\n",(long long)(f[n])); printf("--------------------\n"); } return 0;}