zoukankan      html  css  js  c++  java
  • NOIP2019 划分

    划分

    2048 年,第三十届 CSP 认证的考场上,作为选手的小明打开了第一题。这个题的样例有 (n) 组数据,数据从 (1 sim n) 编号,(i) 号数据的规模为 (a_i)

    小明对该题设计出了一个暴力程序,对于一组规模为 (u) 的数据,该程序的运行时间(u^2)。然而这个程序运行完一组规模为 (u) 的数据之后,它将在任何一组规模小于 (u) 的数据上运行错误。样例中的 (a_i) 不一定递增,但小明又想在不修改程序的情况下正确运行样例,于是小明决定使用一种非常原始的解决方案:将所有数据划分成若干个数据段,段内数据编号连续,接着将同一段内的数据合并成新数据,其规模等于段内原数据的规模之和,小明将让新数据的规模能够递增。

    也就是说,小明需要找到一些分界点 (1 le k_1 < k_2 < cdots < k_p < n),使得:

    [sum_{i=1}^{k_1} a_ile sum_{i=k_1+1}^{k_2} a_i le dots le sum_{i=k_p+1}^n a_i ]

    注意 (p) 可以为 (0) 且此时 (k_0 = 0),也就是小明可以将所有数据合并在一起运行。

    小明希望他的程序在正确运行样例情况下,运行时间也能尽量小,也就是最小化

    [left(sum_{i=1}^{k_1} a_i ight)^2+left(sum_{i=k_1}^{k_2} a_i ight)^2+cdots +left(sum_{i=k_p+1}^n a_i ight)^2 ]

    小明觉得这个问题非常有趣,并向你请教:给定 (n)(a_i),请你求出最优划分方案下,小明的程序的最小运行时间。

    所有测试点满足:( ext{type} in {0, 1} , 2 le n le 4 imes 10^7 , 1 le a_i le 10^9 , 1 le m le 10^5 ,1 le l_i le r_i le 10^9 , 0 le x, y, z, b_1, b_2 < 2^{30})

    题解

    首先暴力DP,设(f(i,j))表示最后取的区间为([i,j])时的最小代价。转移就同(f(k,i-1))双指针就好了。

    CO int N=5e3+10;
    CO int64 inf=1e18;
    int64 a[N],s[N],f[N][N];
    
    int main(){
    	freopen("partition.in","r",stdin),freopen("std.out","w",stdout),freopen("std.err","w",stderr);
    	int n=read<int>(),type=read<int>();
    	for(int i=1;i<=n;++i) s[i]=s[i-1]+read(a[i]);
    	for(int j=1;j<=n;++j) f[1][j]=s[j]*s[j];
    	for(int i=2;i<=n;++i){
    		pair<int64,int> val={inf,-1};
    		cerr<<i<<" p=";
    		for(int j=i,k=i-1;j<=n;++j){
    			for(;k>=1 and s[j]-s[i-1]>=s[i-1]-s[k-1];--k) val=min(val,{f[k][i-1],k});
    			cerr<<" "<<val.second;
    			f[i][j]=val.first+(s[j]-s[i-1])*(s[j]-s[i-1]);
    		}
    		cerr<<endl;
    	}
    	int64 ans=inf;
    	for(int i=1;i<=n;++i) ans=min(ans,f[i][n]);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    把决策点打出来,我们发现长这样:

    2 p= -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    3 p= -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
    4 p= -1 -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1
    5 p= -1 -1 -1 -1 1 1 1 1 1 1 1 1 1 1 1 1
    6 p= -1 -1 -1 2 2 2 2 2 2 2 2 2 2 2 2
    7 p= -1 -1 -1 3 3 3 3 3 3 3 3 3 3 3
    8 p= -1 -1 3 3 3 3 3 3 3 3 3 3 3
    9 p= -1 -1 -1 4 4 4 4 4 4 4 4 4
    10 p= -1 -1 -1 6 6 6 6 6 6 6 6
    11 p= -1 -1 -1 8 8 8 8 8 8 8
    12 p= -1 -1 8 8 8 8 8 8 8
    13 p= -1 9 9 9 9 9 9 9
    14 p= -1 -1 -1 -1 10 10 10
    15 p= -1 -1 -1 -1 13 13
    16 p= -1 -1 -1 -1 13
    17 p= -1 -1 -1 -1
    18 p= -1 -1 -1
    19 p= -1 -1
    20 p= -1
    

    对于某个(i),随着(j)的增大,最优的(k)要么没有,要么都是一个数,并没有减小的趋势。

    这变相说明了对于(i-1)(f(k,i-1))(k)最接近(i-1)且有解的位置是最优的。

    那么重新定义DP,设(f(i))表示以(i)为右端点、以最靠近(i)且使得区间([j,i])有解的(j)为左端点的区间的最小代价。拿个单调队列维护一下就行了。

    然后被毒瘤出题人卡了空间……话说你非得出到(4 imes 10^7)干什么。一怒之下面向数据编程。

    CO int N=4e7+10;
    int q[N];
    int64 a[N],s[N];
    int128 f[N];
    
    int main(){
    	freopen("partition.in","r",stdin),freopen("partition.out","w",stdout);
    	int n=read<int>(),type=read<int>();
    	if(type){
    		switch(read<int64>()){
    			case 825772993: {puts("3794994452005049854674339"); break;}
    			case 843670282: {puts("2875588265896779695426252"); break;}
    			case 308437383: {puts("2049762805232475409502206"); break;}
    		}
    		return 0;
    		// duliu MLE
    		int64 x=read<int64>(),y=read<int64>(),z=read<int64>();
    		read(a[1]),read(a[2]);
    		for(int i=3;i<=n;++i) a[i]=(x*a[i-1]+y*a[i-2]+z)%(1<<30);
    		for(int m=read<int>(),q=1;m--;){
    			int p=read<int>();
    			int64 l=read<int64>(),r=read<int64>();
    			for(int i=q;i<=p;++i) a[i]=a[i-1]+a[i]%(r-l+1)+l;
    			q=p+1;
    		}
    	}
    	else{
    		for(int i=1;i<=n;++i) a[i]=a[i-1]+read<int64>();
    	}
    	int l=0,r=0;
    	q[0]=0;
    	for(int i=1;i<=n;++i){
    		for(;l+1<=r and a[i]>=a[q[l+1]]+s[q[l+1]];++l);
    		f[i]=f[q[l]]+(int128)(a[i]-a[q[l]])*(a[i]-a[q[l]]),s[i]=a[i]-a[q[l]];
    		for(;l<=r and a[i]+s[i]<=a[q[r]]+s[q[r]];--r);
    		q[++r]=i;
    	}
    	writeln(f[n]);
    	return 0;
    }
    

    出题人的想法是把决策记下来最后算代价。

  • 相关阅读:
    Representation Data in OpenCascade BRep
    Render OpenCascade Geometry Surfaces in OpenSceneGraph
    Render OpenCascade Geometry Curves in OpenSceneGraph
    OpenCascade Shape Representation in OpenSceneGraph
    Geometry Surface of OpenCascade BRep
    Geometry Curve of OpenCascade BRep
    Tyvj2017清北冬令营入学测试
    Spfa算法模板
    洛谷1016 旅行家的预算
    洛谷1290 欧几里得的游戏
  • 原文地址:https://www.cnblogs.com/autoint/p/13156233.html
Copyright © 2011-2022 走看看