bzoj4518(单调决策性/分治/斜率优化)

版权声明:如果看得起就随便拿去用吧QWQ https://blog.csdn.net/qkoqhh/article/details/83934816

要保证整数,直接把m^2乘积方差的和式里面变成(mxi-sumx)^2,然后求这个的最小值就可以了

设a为前缀和

设d[i][j]为第i段以j位置为结尾的最小值

d[i][j]=max{d[i-1][k]+(a[j]-a[k]-sumx)^2}

然后这个其实就和bzoj1563差不多了,直接用单调决策性去做就可以了,复杂度O(nlogn)

然后看见别人的代码快得不得了。。于是发现这个直接斜率优化不就好了嘛qaq(学东西学傻了

这个是2次函数比较简单,所以取2个决策点k<v<j,设v为最优决策点,作差可得

(d[i-1][k]-d[i-1][v])/(a[k]-a[v])+a[k]+a[v]<2a[j]-2sumx

由于a[j]递增,因此只要维护一个上凸包就行了。。

然后看到此题有很多解法,又顺手学了波分治(原来分治跑这么快的么orz

首先这个公式其实把平方项拆出来后可以化为m*sum(x[i]^2)-sumx^2

扫描二维码关注公众号,回复: 4146079 查看本文章

主要就是[x,y]是当前的维护区间,[l,r]是决策区间,然后暴力求出mid的决策点pos,又根据决策单调性,[x,mid-1]的决策点必在[l,pos]上,[mid+1,y]的决策点必在[pos,r]上,然后一直分治下去就行了,好写跑得又快。。

解法一:

/*
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 3005
#define nm 200005
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
 
 
 
 
 
int n,m,a[NM],f[NM],v[NM],q[NM],qh,qt;
ll d[NM][NM],s;
 
 
int main(){
    n=read();m=read();
    inc(i,1,n)a[i]=read(),s+=a[i];
    inc(i,1,n)a[i]*=m,a[i]+=a[i-1];
    inc(i,0,m)inc(j,1,n)d[i][j]=inf;
    d[0][0]=0;
    inc(i,1,m){
    q[qh=qt=1]=i-1;mem(f);mem(v);f[i]=i-1;
    inc(j,i,n){
        f[j]=max(f[j],f[j-1]);
        while(qh<=qt&&f[j]!=q[qh])qh++;
        d[i][j]=d[i-1][q[qh]]+sqr(a[j]-a[q[qh]]-s);
        int cnt=j+1;
        while(qh<=qt){
#define fun(t) d[i-1][t]+sqr(a[mid]-a[t]-s)
        cnt=n+1;
        for(int x=j+1,y=n;x<=y;)
            if(fun(q[qt])>fun(j))cnt=mid,y=mid-1;else x=mid+1;
        if(cnt<=v[q[qt]])qt--;else break;
        }
        if(cnt<=n)v[j]=cnt,f[cnt]=j,q[++qt]=j;
    }
    }
    //inc(i,1,m){inc(j,1,n)printf("%lld ",d[i][j]);putchar('\n');}putchar('\n');
    //printf("%lld\n",d[m][n]);
    return 0*printf("%lld\n",d[m][n]/m);
}


解法二:

/*
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 3005
#define nm 200005
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}








int n,m,a[NM],q[NM],qh,qt;
ll s,d[NM][NM];

double slope(int i,int x,int y){return 1.0*(d[i][x]-d[i][y])/(a[x]-a[y])+a[x]+a[y];}

int main(){
    n=read();m=read();
    inc(i,1,n)a[i]=read(),s+=a[i];
    inc(i,1,n)a[i]*=m,a[i]+=a[i-1];
    inc(i,0,m)inc(j,1,n)d[i][j]=inf;
    d[0][0]=0;
    inc(i,1,m){
	q[qh=qt=1]=i-1;
	inc(j,i,n){
	    while(qh<qt&&slope(i-1,q[qh],q[qh+1])<2*a[j]-2*s)qh++;
	    d[i][j]=d[i-1][q[qh]]+sqr(a[j]-a[q[qh]]-s);
	    while(qh<qt&&slope(i-1,q[qt-1],j)>slope(i-1,q[qt],j))qt--;
	    q[++qt]=j;
	}
    }
    //inc(i,1,m){inc(j,1,n)printf("%d ",d[i][j]);putchar('\n');}
    return 0*printf("%lld\n",d[m][n]/m);
}

解法三:

/*
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1LL<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 3005
#define nm 200005
#define pi 3.1415926535897931
using namespace std;
const ll inf=1e9+7;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}






int n,m,a[NM],_x;
ll d[NM][NM],s;

void solve(int x,int y,int l,int r){
    if(x>y||l>r)return;
    int s=inf,m=min(mid-1,r),pos=0;
    inc(i,l,m)if(d[_x-1][i]+sqr(a[mid]-a[i])<s)s=d[_x-1][i]+sqr(a[mid]-a[i]),pos=i;
    d[_x][mid]=s;solve(x,mid-1,l,pos);solve(mid+1,y,pos,r);
}

int main(){
    n=read();m=read();
    inc(i,1,n)a[i]=read(),s+=a[i],a[i]+=a[i-1];
    inc(i,1,n)d[0][i]=inf;
    for(_x=1;_x<=m;_x++)solve(1,n,0,n-1);
    //inc(i,1,m){inc(j,1,n)printf("%d ",d[i][j]);putchar('\n');}
    return 0*printf("%lld\n",d[m][n]*m-sqr(s));
}

4518: [Sdoi2016]征途

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 2319  Solved: 1298
[Submit][Status][Discuss]

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

Source

鸣谢Menci上传

[Submit][Status][Discuss]

猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/83934816