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 }

 

你可能感兴趣的:(classes)