常州day1p5

给一个 n∗m 的矩阵,矩阵的每个格子上有一个不超过 30 的非负整数。 我们定义一条合法的路线是从(1,1)开始只能向右和向下移动到达(n,m)的路线。 定义数列 A1,A2,A3,..,An+m−1 为一条合法路线上的序列,且 Aavg 为该数列的平均值。该路线的 价值为 (n + m−1) 乘上该数列的方差。 即价值的表达式为 (n + m−1)∑n+m−1 i=1 (Ai−Aavg)2。 请找一条价值最小的路线,并输出这个价值。 

对于 100% 的数据,n,m,ai,j ≤ 30

我们发现对于一条确定的路径sigma((a[i]-s)^2)是一个关于s的二次函数,而方差是二次函数的最低点

在数据大的时候会有很多的二次函数,这些二次函数最低点的最小的那个就是答案

这些二次函数的最小值大概会形成一个类似单谷函数的东西。

于是三分。

这是错误的,但是很难卡掉。

小数据暴力

时间复杂度 O(n^2logn)

实际上是标程一个牺牲一定准确性的优化

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<set>
#include<map>
#include<vector>
#define il inline
#define re register
using namespace std;
typedef double db;
int n,m,a[101][101],dir[101],b[101];
db val[101][101],f[101][101];
il db sqr(db x){return x*x;}
il void small(){
    db final=1e50;
    for(int S=(1<<(n+m-2))-1;S>=0;--S){
        for(int i=0;i<n+m-2;i++) dir[i]=((S&(1<<i))>0);
        int u=1,v=1,flag=true;
        db ans,cnt=a[1][1];
        for(int i=0;i<n+m-2;i++){
            if(dir[i]) u++;
            else v++;
            if(!(1<=u&&u<=n&&1<=v&&v<=m)){
                flag=false;break;
            }
            b[i]=a[u][v];cnt+=b[i];
        }
        if(!flag) continue;
        cnt=cnt/(n+m-1);ans=sqr(cnt-a[1][1]);
        for(int i=0;i<n+m-2;i++){
            ans+=sqr(cnt-b[i]);
        }
        final=min(final,ans*(n+m-1));
    }
    printf("%.0lf",final);
}
il db res(db ave){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            val[i][j]=sqr(ave-a[i][j]);
    f[1][1]=val[1][1];
    for(int i=2;i<=m;i++) f[1][i]=f[1][i-1]+val[1][i];
    for(int i=2;i<=n;i++) f[i][1]=f[i-1][1]+val[i][1];
    for(int i=2;i<=n;i++){
        for(int j=2;j<=m;j++)
            f[i][j]=min(f[i-1][j],f[i][j-1])+val[i][j];
    }
    return f[n][m]*(n+m-1);
}
int main(){
    freopen("route.in","r",stdin);
    freopen("route.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    if(n+m<=20){
        small();exit(0);
    }
    db l=0,r=30,m1,m2;
    for(int i=1;i<=100;i++){
        m1=(r-l)/3+l;
        m2=r-(r-l)/3;
    //    cout<<l<<" "<<m1<<" "<<m2<<" "<<r<<endl;
        if(res(m1)<res(m2)) r=m2;
        else l=m1;
    }
    printf("%.0lf",res((l+r)/2));
    return 0;
}
蜉蝣渴望着飞翔,尽管黄昏将至
原文地址:https://www.cnblogs.com/ExiledPoet/p/5771126.html