zoukankan      html  css  js  c++  java
  • 【题解】[SDOI2016]征途

    Link

    题目大意:给定序列,将它划分为(m)段使得方差最小,输出(s^2*m^2)(一个整数)。

    ( ext{Solution:})

    这题我通过题解中的大佬博客学到了一般化方差柿子的写法。

    下面来推柿子:

    [s^2=frac{sum_{i=1}^n (x_i-overline{x})^2}{n}=frac{1}{n}(sum_{i=1}^n x_i^2+n*(frac{ sum_{i=1}^n x_i}{n})^2-2sum_{i=1}^n (x_i* frac{sum_{k=1}^n x_k}{n})) ]

    [s^2=frac{sum_{i=1}^n x_i^2+frac{(sum_{i=1}^n x_i)^2}{n}-2 frac{(sum_{k=1}^n x_i)^2}{n}}{n} ]

    化简得到:

    [s^2=frac{(x_1^2+...+x_n^2)-frac{(sum_{i=1}^n x_i)^2}{n}}{n} ]

    两边乘以(n^2)得到:

    [s^2n^2=nsum_{i=1}^n x_i^2 -(sum_{i=1}^n x_i)^2=nsum_{i=1}^n x_i^2 -sum[n]^2 ]

    其中(sum)是前缀和。最后这个柿子里面,(n,sum)都是常数,最终要处理的就是(sum_{i=1}^n x_i^2).

    (dp[i][l])表示前(i)个元素划分(l)次的最小平方和,有:

    [dp[i][l]=min_{j<i}dp[j][l-1]+(sum[i]-sum[j])^2 ]

    [dp[i][l]=dp[j][l-1]+sum[i]^2+sum[j]^2-2sum[i]sum[j] ]

    [dp[j][l-1]+sum[j]^2=2sum[i]sum[j]+dp[i][l]-sum[i]^2 ]

    [y=dp[j][l-1]+sum[j]^2,k=2sum[i],x=sum[j],b=dp[i][l]-sum[i]^2 ]

    最终目的最小化(dp[i][l])这里就是最小化(b),观察到(2sum[i])这个斜率单调递增,所以我们维护所有大于这个斜率的决策点,做到(O(n).)

    对于这个题,还可以滚动数组优化,虽然这里不需要。

    几个实现细节:前(i)个元素可以划分成(i)段,所以每次枚举起点,它的决策起点应该是划分段数(-1),开始应该是划分段数对应的元素数。因为再往前往后都会导致不合法。

    ( ext{slope})的时候最好用( ext{long double}).顺序不要搞反。当然这个题主要难点是推方差柿子……( ext{WCSL.})

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,m,a[20010],sum[20010];
    int dp[4000][4000],tail,head;
    int q[200010];
    int X(int x){return sum[x];}
    int Y(int x,int p){return dp[x][p-1]+sum[x]*sum[x];}
    long double slope(int x,int y,int p){return (long double)(Y(y,p)-Y(x,p))/(X(y)-X(x));}
    //dp[i][l]=dp[j][l-1]+(sum[i]-sum[j])^2
    signed main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;++i)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i],dp[i][1]=sum[i]*sum[i];
    	for(int p=2;p<=m;p++){
    		head=tail=1;
    		q[head]=p-1;
    		for(int i=p;i<=n;++i){
    			while(head<tail&&slope(q[head],q[head+1],p)<2.0*sum[i])head++;
    			dp[i][p]=dp[q[head]][p-1]+(sum[i]-sum[q[head]])*(sum[i]-sum[q[head]]);
    			while(head<tail&&slope(q[tail-1],q[tail],p)>slope(q[tail-1],i,p))tail--;
    			q[++tail]=i;
    		}
    	}
    	printf("%lld
    ",m*dp[n][m]-sum[n]*sum[n]);
    	return 0;
    }
    

    附上推柿子时( ext{word})上的东西:

    (Dp[i][l]=dp[j][l-1]+(sum[i]-sum[j])^2)
    (Dp[i]][l]=dp[j][l-1]+sum[i]^2+sum[j]^2-2sum[i]sum[j])
    (Dp[j][l-1]+sum[j]^2=2sum[i]sum[j]+dp[i][l]-sum[i]^2)
    (Y=dp[j][l-1]+sum[j]^2,k=2sum[i],x=sum[j],b=dp[i][l]-sum[i]^2)
    最小化(b),即可

    (Ans=-sum[n]^2+m*dp[n][m])

  • 相关阅读:
    You are not late! You are not early!
    在同一个服务器(同一个IP)为不同域名绑定的免费SSL证书
    Vue.js Is Good, but Is It Better Than Angular or React?
    It was not possible to find any compatible framework version
    VS增加插件 Supercharger破解教程
    Git使用ssh key
    Disconnected: No supported authentication methods available (server sent: publickey)
    VS 2013打开.edmx文件时报类型转换异常
    asp.net MVC4 框架揭秘 读书笔记系列3
    asp.net MVC4 框架揭秘 读书笔记系列2
  • 原文地址:https://www.cnblogs.com/h-lka/p/12828645.html
Copyright © 2011-2022 走看看