[Sdoi2016]征途

Description

Pine开始了从S地到T地的征途。
从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
帮助Pine求出最小方差是多少。
设方差是v,可以证明,v×m^2是一个整数。为了避免精度误差,输出结果时输出v×m^2。
 

Input

第一行两个数 n、m。
第二行 n 个数,表示 n 段路的长度
 

Output

 一个数,最小方差乘以 m^2 后的值

 

Sample Input

5 2
1 2 5 8 6

Sample Output

36

HINT

 

1≤n≤3000,保证从 S 到 T 的总路程不超过 30000

 
 
 

 

 1 #include<iostream>
 2 #include<string>
 3 #define LL long long 
 4 using namespace std;
 5 
 6 int n,m,L[3005]={0};
 7 LL f[3005]={0},g[3005]={0};
 8 
 9 LL pow(long long x){
10     return x*x;
11     }
12 
13 LL cal(int k,int j){
14        return g[k]+pow(L[k])-2*L[j]*L[k];
15        }
16 
17 double slope(int j,int k,int i){
18        double y2=g[k]+pow(L[k]);
19        double y1=g[j]+pow(L[j]);
20        double x2=2*L[k];
21        double x1=2*L[j];
22        
23        double y3=g[i]+pow(L[i]);
24        double x3=2*L[i];
25        
26        return (y2-y1)/(x2-x1)>(y3-y2)/(x3-x2);
27        }
28 
29 int main()
30 {
31     cin>>n>>m;
32     
33     for(int i=1;i<=n;++i)
34     {
35       cin>>L[i];
36       L[i]+=L[i-1];
37             }
38     
39     for(int i=1;i<=n;++i)
40     g[i]=pow(L[i]);
41     
42     for(int i=2;i<=m;++i)
43     {
44       int Q[3005]={0},head=0,tail=0;
45       for(int j=1;j<=n;++j)
46       {
47          while(head<tail&&cal(Q[head],j)>cal(Q[head+1],j)) head++;
48          int k=Q[head];
49          f[j]=g[k]+pow(L[j]-L[k]);
50          
51          while(head<tail&&slope(Q[tail-1],Q[tail],j)) tail--;
52          Q[++tail]=j;     
53               }
54       
55       for(int j=1;j<=n;++j) g[j]=f[j];
56             }
57     
58     cout<<m*g[n]-pow(L[n])<<endl;
59     
60     
61    // system("pause"); 
62     
63     } 

 

posted on 2017-11-30 16:33  怡红公子  阅读(216)  评论(0编辑  收藏  举报