首页 > 其他分享 >[CF321E]Ciel and Gondolas

[CF321E]Ciel and Gondolas

时间:2022-10-18 14:23:41浏览次数:50  
标签:ch Ciel int sum Gondolas CF321E leq include getchar

做题时间:2022.10.18

\(【题目描述】\)

有 \(n(n\leq 4000)\) 个人按 \(1\rightarrow n\) 编号,并按这个顺序站成一排,现在要将他们分成连续的 \(k(k\leq \min(n,800))\)组,对于任意不相同的人 \(i,j\),若他们分在一组,则会产生 \(p_{i,j}(0\leq p_{i,j}\leq 9)\) 的沮丧值(保证 \(p_{i,i}=0\)),现要求最小的沮丧值之和。

\(【输入格式】\)

第一行两个整数 \(n,k\)

接下来 \(n\) 行每行 \(n\) 个整数表示 \(p_{i,j}\)

\(【输出格式】\)

一行一个整数表示答案

\(【考点】\)

决策单调性优化dp

\(【做法】\)

设 \(f_{i,j}\) 表示前 \(i\) 个人分成 \(j\) 组的最小沮丧值之和。有:

\[f_{i,j}=\min(f_{k-1,j-1}+\sum\limits_{a=k}^{i}\sum\limits_{b=k}^i p_{i,j}) \]

由于 \(p_{i,j}\geq 0\),因此肯定满足决策单调性和四边形不等式,这种2D/1D的转移方程,可以直接进行分治,复杂度 \(O(nk\log n)\),也可以使用四边形不等式优化,记录决策点减少枚举复杂度,复杂度 \(O(nk)\)

\(【代码】\)

分治:

#include<cstdio>
#include<iomanip>
#include<cstring>
using namespace std;
const int N=4e3+50,M=805;
int f[N][M],n,k;
int sum[N][N],p[N][N];
inline int Read()
{
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+ch-48;
		ch=getchar();
	}
	return x;
}
int val(int l,int r)
{
	return sum[r][r]-sum[l-1][r]-sum[r][l-1]+sum[l-1][l-1];
}
void dp(int l,int r,int jl,int jr,int cur)
{
	if(l>r) return ;
	int mid=(l+r)>>1;
	int num=0;
	for(int k=jl;k<=min(jr,mid);k++){
		int t=f[k-1][cur-1]+val(k,mid);
		if(t<f[mid][cur]){
			f[mid][cur]=t;
			num=k;
		}
	}
	dp(l,mid-1,jl,num,cur);
	dp(mid+1,r,num,jr,cur);
}
void pre()
{
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+p[i][j];
		}
	}
}
int main()
{
	n=Read(),k=Read();
	for(int i=1;i<=n;i++){ 
		for(int j=1;j<=n;j++) p[i][j]=Read();
	}
	pre();
	
	memset(f,0x3f3f3f,sizeof f);
	f[0][0]=0;
	for(int i=1;i<=k;i++) dp(1,n,1,n,i);
	printf("%d\n",f[n][k]/2);
	return 0;
}

四边形不等式优化:

#include<cstdio>
#include<iomanip>
#include<cstring>
using namespace std;
const int N=4e3+50,M=805;
int f[M][N],n,k;
int sum[N][N],p[N][N],m[N][N];
inline int Read()
{
	int x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+ch-48;
		ch=getchar();
	}
	return x;
}
int val(int l,int r)
{
	return sum[r][r]-sum[l-1][r]-sum[r][l-1]+sum[l-1][l-1];
}

void pre()
{
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+p[i][j];
		}
	}
}
int main()
{
	n=Read(),k=Read();
	for(int i=1;i<=n;i++){ 
		for(int j=1;j<=n;j++) p[i][j]=Read();
	}
	pre();
	
	memset(f,0x3f3f3f,sizeof f);
	f[0][0]=0;
	for(int i=1;i<=n;i++) m[0][i]=1,m[i][n+1]=n;
	for(int i=1;i<=k;i++){
		for(int j=n;j>=1;j--){
			for(int k=m[i-1][j];k<=m[i][j+1];k++){
				int t=f[i-1][k-1]+val(k,j);
				if(t<f[i][j]) f[i][j]=t,m[i][j]=k;
			}
		}
	}	
	printf("%d\n",f[k][n]/2);
	return 0;
}

标签:ch,Ciel,int,sum,Gondolas,CF321E,leq,include,getchar
From: https://www.cnblogs.com/Unlimited-Chan/p/16802420.html

相关文章

  • cf321 C. Ciel the Commander
    题意:用'A'~'Z'​给一棵树上的点染色,要求若两点字符相同则两点间的路径上一定有字符更小的点。思路:法一:点分治树的重心能把树划分成每块大小不超过\(n/2\)的连通块......