bzoj1563(單調決策性DP)
這個題一看數字就很爆炸啊。。不過先不管他。。
先對長度+1,然後取個字首和設為a
設d[i]為取到i個句子且當前行以i句結尾的最小代價
d[i]=max{d[j]+|a[i]-a[j]-L-1|^p}
顯然f(x)=|x|^p是個下凸函式,即x越大導數越大。。
然後考慮2個決策點j<k<i
如果d[j]+|a[i]-a[j]-L-1|^p>d[k]+|a[i]-a[k]-L-1|^p,那麼此後j就不會比k更優了。。
所以用單調佇列存遞增的決策點,用上面的式子去隊尾就可以了。。
然而數非常爆炸,在比較的時候很麻煩,於是用long double(double都不行= =)來做大數比較,雖然有精度誤差但是問題不大。。
複雜度O(Tnlognlogp),常數巨大。。
/** * ┏┓ ┏┓ * ┏┛┗━━━━━━━┛┗━━━┓ * ┃ ┃ * ┃ ━ ┃ * ┃ > < ┃ * ┃ ┃ * ┃... ⌒ ... ┃ * ┃ ┃ * ┗━┓ ┏━┛ * ┃ ┃ Code is far away from bug with the animal protecting * ┃ ┃ 神獸保佑,程式碼無bug * ┃ ┃ * ┃ ┃ * ┃ ┃ * ┃ ┃ * ┃ ┗━━━┓ * ┃ ┣┓ * ┃ ┏┛ * ┗┓┓┏━┳┓┏┛ * ┃┫┫ ┃┫┫ * ┗┻┛ ┗┻┛ */ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<cmath> #include<map> #include<stack> #include<set> #include<bitset> #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,l,r) for(int i=l;i>=r;i--) #define link(x) for(edge *j=h[x];j;j=j->next) #define mem(a) memset(a,0,sizeof(a)) #define ll long long #define eps 1e-8 #define succ(x) (1LL<<(x)) #define lowbit(x) (x&(-x)) #define sqr(x) ((x)*(x)) #define mid (x+y>>1) #define NM 100005 #define nm 200005 #define pi 3.1415926535897931 using namespace std; const ll inf=1e18; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int n,L,p,qh,qt,q[NM],f[NM],v[NM],a[NM]; char _s[50]; long double d[NM]; long double qpow(long double x,int t){return t?qpow(sqr(x),t>>1)*(t&1?x:1):1;} int main(){ freopen("data.in","r",stdin); int _=read();while(_--){ mem(d);mem(f);mem(v); n=read();L=1+read();p=read(); inc(i,1,n){scanf("%s",_s);a[i]=a[i-1]+1+strlen(_s);} q[qh=qt=1]=0; inc(i,1,n){ f[i]=max(f[i],f[i-1]); while(qh<=qt&&f[i]!=q[qh])qh++; d[i]=d[q[qh]]+qpow(abs(a[i]-a[q[qh]]-L),p); int s=i+1; while(qh<=qt){ s=n+1; #define fun(t) d[t]+qpow(abs(a[mid]-a[t]-L),p) for(int x=i+1,y=n;x<=y;) if(fun(q[qt])>fun(i))s=mid,y=mid-1;else x=mid+1; if(s<=v[q[qt]])qt--;else break; } if(s<=n)f[s]=i,v[i]=s,q[++qt]=i; } //inc(i,1,n)printf("%d ",a[i]-a[i-1]);putchar('\n'); //inc(i,1,n)printf("%d ",f[i]);putchar('\n'); //inc(i,1,n)printf("%lld ",d[i]);putchar('\n'); if(d[n]>inf)printf("Too hard to arrange\n");else printf("%lld\n",(ll)d[n]); printf("--------------------\n"); } return 0; }
1563: [NOI2009]詩人小G
Time Limit: 100 Sec Memory Limit: 64 MB
Submit: 3017 Solved: 1017
[Submit][Status][Discuss]
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
1 1004 6
poet
Sample Output
108
--------------------
32
--------------------
Too hard to arrange
--------------------
1000000000000000000
--------------------
【樣例說明】
前兩組輸入資料中每行的實際長度均為6,後兩組輸入資料每行的實際長度均為4。一個排版方案中每行相鄰兩個句子之間的空格也算在這行的長度中(可參見樣例中第二組資料)。每行末尾沒有空格。
HINT
總共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。
Source