标签:
原题面
题意:每一个线段有一个长度,有一个标准长,现在要把这些线段按照顺序分行,每行的不和谐值等于标准长和该行线段总长的差的绝对值的p次方。现在要求最小的不和谐值之和。
开始的时候完全读错题了,以为p==2 for ever.真是太天真。后来看数据范围才发现。我真是面向数据编程?
n^2的dp是一眼秒的。然后如果是p=2,那就是一个非常像玩具装箱的斜率优化dp。对于4、5的数据范围。可以想到用贪心优化dp.因为每一行的长度不会通过拼接线段(线段条数>=2)达到2*标准长,这样会得到很劣的答案,可以直接去掉(好贪的贪心)。
感觉考场70分已经很高了,但实际上这三种情况打起来,代码4k打不住。我们需要把dp优化到o(n)或者o(nlogn),这通过死早的数学简直分析不出来。所以来打一个表看一下,很显然,转移被分成连续的递增的区间!也就是所谓的决策单调性。我证不出来,但假设就是一个决策单调性的题目,就是nlogn裸题。很符合数据(面向数据)。然后就是细节:
①简述决策单调性做法:维护决策相同的一段段连续的区间。用一个类队列维护。首先当前如果要得到f[i],一定从j<i转移过来,此时i的决策应该已经由i之前的维护得知。现在得到了f[i],要进行一步Update(i),说白了就是找到用i做决策的区间。对于已经存在的末尾的区间d[t],如果它的左端点在i右侧,且从i转移到这个区间的左端点比原有转移更优(那现在原有的决策没有存在的必要)将它与第t-1个区间合并,并删除原有区间(t--) ,现在得到一个d[t],我们想知道这个区间的从左开始有多长的一段用i来做决策不如原有决策优,再向右的区间就应该用i作为决策(根据决策单调性),二分一下就好。
②运算中会出现爆long long,开始尝试使用double判断是否超限制,再用long long (算出精确的值),但是不知道哪里出了问题调不出来,所有直接忽视精度问题上long double了。竟然A了。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #define maxn 120000 7 #define mxll 1e18 8 using namespace std; 9 long double f[maxn]; 10 long double sum[maxn]; 11 int q[maxn],ll[maxn],rr[maxn],len[maxn]; 12 int n,m,limit,p,cas,head,tail; 13 long double px(long double a) 14 { if (a<0) a=-a;long double mid=1; 15 for (int i=1;i<=p;i++) mid*=a; return mid; 16 } 17 long double clac(int i,int j) 18 { return f[j]+px(sum[i]-sum[j]+i-j-1-limit);} 19 void update(int i) 20 { while (ll[tail]>i&&clac(ll[tail],q[tail])>clac(ll[tail],i)) rr[tail-1]=rr[tail--]; 21 int l=ll[tail],r=rr[tail],pos=r+1; 22 while (l<=r) 23 { int mid=(l+r)>>1; 24 if (clac(mid,q[tail])>clac(mid,i)) r=mid-1,pos=mid;else l=mid+1; 25 } 26 if (pos<=rr[tail]) 27 { ll[tail+1]=pos;rr[tail+1]=rr[tail]; 28 rr[tail]=pos-1;q[++tail]=i; 29 } 30 } 31 void solve() 32 { head=tail=1; 33 ll[head]=1; rr[head]=n; 34 for (int i=1;i<=n;i++) 35 { if (i>rr[head]) head++; 36 f[i]=clac(i,q[head]);update(i); 37 } 38 } 39 void init() 40 { scanf("%d%d%d",&n,&limit,&p); 41 char s[100]; 42 for (int i=1;i<=n;i++) 43 { scanf("%s",s);len[i]=strlen(s); 44 sum[i]=sum[i-1]+len[i]; 45 } 46 } 47 void write() 48 { if (f[n]>mxll) printf("Too hard to arrange\n"); 49 else printf("%lld\n",(long long)f[n]); 50 printf("--------------------\n"); 51 } 52 int main() 53 { scanf("%d",&cas); 54 while (cas--) 55 { init();solve();write();} 56 return 0; 57 }
Bzoj 1563: [NOI2009]诗人小G(决策单调性优化)
标签:
原文地址:http://www.cnblogs.com/ShallWe2000/p/5326745.html