ZOJ-3399 Classes Division 单调队列优化DP

  题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3399

  要注意此题的班级必须是连续的!!!

  转移方程容易想出来:f[i][j]表示前 i 个班级分 j 个学生的最优解,那么 f[i][j]=Min{ f[i-1][k] + Σ(x[k]-L)^2*g[i] | j-B<=k<=j-A },然后预处理 Σ(x[k]-L)^2 -> s[k]。则 f[i][j]=Min{  ( f[i-1][k] - s[k]*g[i] ) + s[j]*k | j-B<=k<=j-A },注意到 f[i][j] 只与 k 有关,因此我们用一个单调队列来维护最优值优化算法。

  PS:一定要注意输出用%lld,不能用%I64d,我因为这个WA到蛋碎。。。

 1 //STATUS:C++_AC_740MS_656KB
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #include<math.h>
 6 #include<iostream>
 7 #include<string>
 8 #include<algorithm>
 9 #include<vector>
10 #include<queue>
11 #include<stack>
12 #include<map>
13 using namespace std;
14 #define LL long long
15 #define pii pair<int,int>
16 #define Max(a,b) ((a)>(b)?(a):(b))
17 #define Min(a,b) ((a)<(b)?(a):(b))
18 #define mem(a,b) memset(a,b,sizeof(a))
19 #define lson l,mid,rt<<1
20 #define rson mid+1,r,rt<<1|1
21 const int N=10010,INF=0x3f3f3f3f,MOD=4001,STA=1000010;
22 const LL LNF=0x3f3f3f3f3f3f3f3f;
23 const double DNF=100000000000;
24 
25 LL s[N],f[2][N],q[N][2],x[N],g[210];
26 int n,K,A,B,L;
27 
28 int main()
29 {
30  //   freopen("in.txt","r",stdin);
31     int i,j,k,KL,T,p,front,rear,sum;
32     LL ans;
33     while(~scanf("%d%d%d%d",&n,&K,&A,&B))
34     {
35         ans=LNF;
36         s[0]=sum=0;
37         for(i=1;i<=n;i++){
38             scanf("%lld",&x[i]);
39             sum+=x[i];
40         }
41         L=sum/n;
42         for(i=1;i<=K;i++)
43             scanf("%lld",&g[i]);
44         for(i=1;i<=n;i++){
45             s[i]=s[i-1]+(x[i]-L)*(x[i]-L);
46         }
47         mem(f,INF);
48         f[0][0]=0;
49         for(i=p=1;i<=K;i++,p=!p){
50             mem(f[p],INF);
51             front=rear=0;
52             j=i*A;
53             k=Max(0,j-B);
54             for(;k<j-A;k++){
55                 while(f[!p][k]-s[k]*g[i]<=q[rear-1][1] && front<rear)
56                     rear--;
57                 q[rear][0]=k;
58                 q[rear++][1]=f[!p][k]-s[k]*g[i];
59             }
60             for(;j<=i*B && j<=n;j++){
61                 k=Min(j-A,(i-1)*B);
62                 while(f[!p][k]-s[k]*g[i]<=q[rear-1][1] && front<rear)
63                     rear--;
64                 q[rear][0]=k;
65                 q[rear++][1]=f[!p][k]-s[k]*g[i];
66                 while(q[front][0]<j-B)front++;
67                 f[p][j]=q[front][1]+s[j]*g[i];
68             }
69             if(f[p][n]<ans){
70                 ans=f[p][n];
71                 KL=i;
72                 T=n-q[front][0];
73             }
74         }
75 
76         if(ans!=LNF)printf("%lld %d %d\n",ans,KL,T);
77         else printf("No solution.\n");
78     }
79 
80     return 0;
81 }

 

posted @ 2013-04-02 01:14  zhsl  阅读(366)  评论(0编辑  收藏  举报