[SDOI2016]征途
题目描述
Pine开始了从S地到T地的征途。
从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站。
Pine计划用m天到达T地。除第m天外,每一天晚上Pine都必须在休息站过夜。所以,一段路必须在同一天中走完。
Pine希望每一天走的路长度尽可能相近,所以他希望每一天走的路的长度的方差尽可能小。
帮助Pine求出最小方差是多少。
设方差是v,可以证明,v\times m^2v×m2是一个整数。为了避免精度误差,输出结果时输出v\times m^2v×m2。
毒瘤sdoi出的毒瘤题。
先是卡空间,又是卡时间,最后做了3个点才做完。
正经事:
1.答案是( sigma(m*xi - sn)^2 ) / m。
2.普通dp一定过不了,由于其满足斜率优化以及决策单调,我们可以用斜率优化dp来做。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 3050 ll n,m; ll s[N],f[N][N]; int q[N][N],h[N],t[N]; ll x(int i) { return 1ll*m*s[i]+s[n]; } ll k(int i) { return 2ll*m*s[i]; } ll y(int i,ll d) { return f[i][d]+x(i)*x(i); } ll b(int i) { return m*m*s[i]*s[i]; } int main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&s[i]),s[i]+=s[i-1]; memset(f,0x3f,sizeof(f)); f[0][0]=0; for(int d=0;d<m;d++) { for(int i=max(d-1,0);i<=n;i++) { while(h[d]<t[d]&&(y(q[h[d]+1][d],d)-y(q[h[d]][d],d)<=k(i)*(x(q[h[d]+1][d])-x(q[h[d]][d]))))h[d]++; f[i][d+1]=y(q[h[d]][d],d)-k(i)*x(q[h[d]][d])+b(i); while(h[d+1]<t[d+1]&&((y(i,d+1)-y(q[t[d+1]][d+1],d+1))*(x(q[t[d+1]][d+1])-x(q[t[d+1]-1][d+1]))<=(y(q[t[d+1]][d+1],d+1)-y(q[t[d+1]-1][d+1],d+1))*(x(i)-x(q[t[d+1]][d+1]))))t[d+1]--; q[++t[d+1]][d+1] = i; } } printf("%lld\n",f[n][m]/m); return 0; }