bzoj 1010: [HNOI2008]玩具装箱toy
这道题是一道很简单的DP,方程很容易列出来,
只不过要优化,因为n^2过不了。
膜拜了一下搞神的《浅析1D1D动态规划的优化(zzx)》
既可以用斜率优化也可以用单调性优化。
单调性证明就不说了。
斜率优化还不太懂所以只写了单调性优化
1 /* 2 ID:WULALA 3 PROB:bzoj1010 4 LANG:C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath> 10 #include <iostream> 11 #include <ctime> 12 #include <set> 13 #define N 50008 14 #define M 15 #define mod 16 #define mid(l,r) ((l+r) >> 1) 17 #define INF 0x7ffffff 18 using namespace std; 19 20 int n,L,que[N],st[N],l = 1,r = 1; 21 long long f[N],pre[N]; 22 inline long long sqr(long long a) 23 { 24 return (a*a); 25 } 26 27 inline long long cal(int s,int t) 28 { 29 return (f[s] + sqr(t - s - 1 + pre[t] - pre[s] - L)); 30 } 31 32 int find(int a) 33 { 34 int bot = 1,top = r + 1; 35 while (bot != top) 36 { 37 if (st[que[mid(bot,top)]] > a) top = mid(bot,top); 38 else bot = mid(bot,top) + 1; 39 }//寻找第一个比a小可以先找第一个比a大 40 return (bot - 1); 41 } 42 43 int work() 44 { 45 memset(que,255,sizeof(que)); 46 que[1] = 0; 47 st[0] = 1; 48 for (int i = 1;i <= n+1;i++) st[i] = n + 1;//方便查找 49 for (int i = 1;i <= n;i++) 50 { 51 f[i] = cal(que[find(i)],i); 52 while (st[que[r]] > i && r && cal(i,st[que[r]]) < cal(que[r],st[que[r]])) r--; 53 if (!r) 54 { 55 que[++r] = i; 56 st[i] = i; 57 continue ; 58 } 59 int bot = st[que[r]],top = n + 1; 60 while (bot != top) 61 { 62 if (cal(que[r],mid(bot,top)) >= cal(i,mid(bot,top))) top = mid(bot,top); 63 else bot = mid(bot,top) + 1; 64 } 65 if (bot == n + 1) continue ;//此决策无法入栈 66 que[++r] = i; 67 st[i] = bot; 68 } 69 } 70 71 int main() 72 { 73 scanf("%d%d",&n,&L); 74 for (int i = 1;i <= n;i++) 75 { 76 scanf("%d",&pre[i]); 77 pre[i] += pre[i-1]; 78 } 79 work(); 80 printf("%lld",f[n]); 81 return 0; 82 }
昨天和洛神聊了下天,把斜率优化学了,顺手写了一下
1 /* 2 ID:WULALA 3 PROB:bzoj1010 slope 4 LANG:C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath> 10 #include <iostream> 11 #include <ctime> 12 #include <set> 13 #define N 50008 14 #define M 15 #define mod 16 #define mid(l,r) ((l+r) >> 1) 17 #define INF 0x7ffffff 18 using namespace std; 19 20 int n,L,que[N],l,r; 21 long long pre[N],f[N]; 22 23 inline long long sqr(long long a) 24 { 25 return (a*a); 26 } 27 28 inline long long cal(int s,int t) 29 { 30 return (f[s] + sqr(t - s - 1 + pre[t] - pre[s] - L)); 31 } 32 33 void init() 34 { 35 scanf("%d%d",&n,&L); 36 for (int i = 1;i <= n;i++) 37 { 38 scanf("%lld",&pre[i]); 39 pre[i] += pre[i-1]; 40 } 41 memset(que,255,sizeof(que)); 42 l = r = que[0] = 0; 43 } 44 45 long long det(int o,int a,int b) 46 { 47 long long xo = pre[o],yo = f[o] + sqr(pre[o]) - 2 * l * pre[o]; 48 long long xa = pre[a],ya = f[a] + sqr(pre[a]) - 2 * l * pre[a]; 49 long long xb = pre[b],yb = f[b] + sqr(pre[b]) - 2 * l * pre[b]; 50 xa -= xo; xb -= xo; 51 ya -= yo; yb -= yo; 52 return (xa * yb - xb * ya); 53 } 54 55 void debug() 56 { 57 printf("\n"); 58 for (int i = l;i <= r;i++) printf("%d ",que[i]); 59 printf("\n"); 60 for (int i = 1;i <= n;i++) printf("%d ",f[i]); 61 printf("\n"); 62 } 63 64 void work() 65 { 66 for (int i = 1;i <= n;i++) 67 { 68 while (cal(que[l],i) >= cal(que[l+1],i) && que[l+1] != -1) l++; 69 f[i] = cal(que[l],i); 70 if (f[i] < 0) printf("error: i"); 71 while (det(que[r-1],que[r],i) < 0 && r > l) r--; 72 que[++r] = i; 73 // debug(); 74 } 75 } 76 77 int main() 78 { 79 init(); 80 work(); 81 printf("%lld\n",f[n]); 82 return 0; 83 }