码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-03-27 21:22:02      阅读:407      评论:0      收藏:0      [点我收藏+]

标签:

 

原题面

带有详细证明的转这里

题意:每一个线段有一个长度,有一个标准长,现在要把这些线段按照顺序分行,每行的不和谐值等于标准长和该行线段总长的差的绝对值的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 }
CODE

 

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

标签:

原文地址:http://www.cnblogs.com/ShallWe2000/p/5326745.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!