Codeforce 321E Ciel and Gondolas(dp优化)

Ciel and Gondolas

题目

Fox Ciel is in the Amusement Park. And now she is in a queue in front of the Ferris wheel. There are n people (or foxes more precisely) in the queue: we use first people to refer one at the head of the queue, and n-th people to refer the last one in the queue.

There will be k gondolas, and the way we allocate gondolas looks like this:

  • When the first gondolas come, the q1 people in head of the queue go into the gondolas.
  • Then when the second gondolas come, the q2 people in head of the remain queue go into the gondolas.

        ...

  • The remain qk people go into the last (k-th) gondolas.

Note that q1, q2, ..., qk must be positive. You can get from the statement that 

 and qi > 0.

You know, people don't want to stay with strangers in the gondolas, so your task is to find an optimal allocation way (that is find an optimal sequence q) to make people happy. For every pair of people i and j, there exists a value uij denotes a level of unfamiliar. You can assume uij = uji for all i, j (1 ≤ i, j ≤ n) and uii = 0 for all i (1 ≤ i ≤ n). Then an unfamiliar value of a gondolas is the sum of the levels of unfamiliar between any pair of people that is into the gondolas.

A total unfamiliar value is the sum of unfamiliar values for all gondolas. Help Fox Ciel to find the minimal possible total unfamiliar value for some optimal allocation.

题意

        n个人,分k次乘坐,每一次乘坐的不愉快值等于这一次乘坐的人两两之间不愉快值之和,且每次乘坐的人一定是连续的,求k次乘坐的不愉快值之和的最小值

思路

        这里我们设w[i][j]表示,区间i到j这一段人一起乘坐会产生的不愉快值,我们可以用二维前缀和的方法去预处理出这一个值,这样可以在dp时优化掉一个n的复杂度。

        我们可以想到一个最简单的dp思路,枚举长度,枚举左端点,枚举中间节点,用这样的dp显然是可行的,但是复杂度在kn^{2},显然是为T 的。

        然后我们可以发现,对于a,b,c,d(a\leqslant b\leqslant c \leqslant d),一定存在的关系式是w[a,c]+w[b,d]\leqslant w[a,d]+w[b,c],可以发现这是满足四边形不等式的,所以可以套用板子进行优化处理。

        最后,题目的时间比较卡,可以用快读优化。

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int N = 4100;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f;

int a[N][N],w[N][N],dp[N],res[N];
inline ll read() {
	ll ans=0,f=1;
	char c=getchar();
	while(c<'0' || c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9') {
		ans=(ans<<1)+(ans<<3)+(c^48);
		c=getchar();
	}
	return ans*f;
}
void check(int l,int r,int L,int R) {
	if(l>r) return ;
	int mid=(l+r)>>1,MID;
	for(int i=L; i<=min(R,mid); i++) {
		if(dp[mid]>res[i-1]+w[i][mid]) {
			dp[mid]=res[i-1]+w[i][mid];
			MID=i;
		}
	}
	check(l,mid-1,L,MID);
	check(mid+1,r,MID,R);
}
void solve() {
	int n,k;
	scanf("%lld%lld",&n,&k);
	for(int i=1; i<=n; i++) {
		for(int j=1; j<=n; j++) {
			a[i][j]=read();
			a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
		}
	}
	for(int i=1; i<=n; i++) {
		for(int j=i+1; j<=n; j++) {
			w[i][j]=(a[j][j]+a[i-1][i-1]-a[j][i-1]-a[i-1][j])/2;
		}
	}
	for(int i=1; i<=n; i++) dp[i]=w[1][i];
	for(int i=2; i<=k; i++) {
		for(int j=1; j<=n; j++) {
			res[j]=dp[j];
			dp[j]=INF;
		}
		check(1,n,1,n);
	}

	printf("%lld\n",dp[n]);
}
signed main() {
	int t=1;
	while(t--)solve();
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心刍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值