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显然是可行的,但是复杂度在,显然是为T 的。
然后我们可以发现,对于,一定存在的关系式是
,可以发现这是满足四边形不等式的,所以可以套用板子进行优化处理。
最后,题目的时间比较卡,可以用快读优化。
#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;
}