跳到主要内容

Holding

· 阅读需 5 分钟

[COCI 2019/2020 #4] Holding​

Details

题目背景

Ivica 有一个由 NN 家克罗地亚公司组成的集团,但他的集团正面临着困难。他的企业承受着巨额的负债,所以政 府派遣律师没收了他的一切财产。

但我们发现,尽管他有巨额债务在身,他依然与政 府达成协议,留住了部分企业。他留住的是哪些?我们也知道了。

题目描述

律师们把 Ivica 的公司的 NN 份债务文件摆在桌上。第一家公司的债务为 A1A_1 ,第二家公司的债务为 A2A_2 ,依次类推。

Ivica 与政 府达成协议,使它留下桌上 [L,R][L,R] 区间的所有文件所对应的公司,但他需要承担 AL,AL+1…ARA_L,A_{L+1}\ldots A_R 的所有债务,其中 LL 和 RR 代表桌子上一系列文件中的位置。

幸运的是,律师们也是腐败。他们可以让他以 ∣i−j∣|i-j| 的价格交换当前放在位置 ii 和位置 jj 的文件。

Ivica 有点绝望。他口袋里只有 KK 元钱,他现在想把这些钱花在这里,使得他的需要承担的债务尽可能少。

请帮他达成目标。

输入格式

第一行四个整数 N,L,R,KN,L,R,K。

第二行 NN 个整数,第 ii 个表示 AiA_i。

输出格式

一行一个整数,表示花不超过 KK 元后负债的最小值。

输入输出样例 #1

输入 #1

3 2 2 1
1 2 3

输出 #1

1

输入输出样例 #2

输入 #2

5 2 3 3
21 54 12 2 0

输出 #2

12

输入输出样例 #3

输入 #3

6 4 6 100
1 2 3 4 5 6

输出 #3

6

说明/提示

【数据规模与约定】

子任务编号特殊限制分值
11N≤13N\le 13,R=NR=N2020
22N≤50N\le 50,R=NR=N3030
33N≤50N\le 503030
44无特殊限制2020

对于 100%100\% 的数据,保证 1≤N≤1001\le N\le 100,1≤L≤R≤N1\le L\le R\le N,1≤K≤1041\le K\le 10^4,1≤Ai≤1061\le A_i\le 10^6。

【提示与帮助】

题目译自 COCI 2019/2020 CONTEST #4 T3 Holding

在 COCI 中,本题分值为 110110 分。


分析​

容易发现交换 i,ji,j 两个元素并花费∣i−j∣∣i−j∣元,相当于进行了∣i−j∣∣i−j∣次邻项交换

所以将问题转化为进行不超过 k 次邻项交换使得 [l,r] 区间内的元素之和最小

将这些元素在原数列中的下标按照从小到大排列记为p1​,p2​,⋯,pmp_1​,p_2​,⋯,p_m​,那么在最优决策下,p1p1移动到了ll,p2​p2​移动到了l+1,……,pil+1,……,pi移动到了l+i−1l+i−1

因为如果移动两个元素i,ji,j时,路径发生了交叉,那么必然发生了交换i,ji,j两个元素的情形,这一定会更劣

那么状态设计就非常简单

fi,j,kf_{i,j,k}表示前ii个数,选择了jj个,花费了恰好kk元的情况下,选出的元素的最小值,容易得到状态转移方程:

fi,j,k​=minfi−1,j,k​,fi−1,j−1,k−∣l+j−i−1∣​+ai​f_{i,j,k}​=min{f_{i−1,j,k}​,f_{i−1,j−1,k−∣l+j−i−1∣​}+a_i​ }

时间复杂度为O(n2k)O(n^2k),使用滚动数组滚掉第一维空间复杂度为O(nk)O(nk)


AC代码​

Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair< int,int >
#define QWQ return 0;
#define QAQ return

const int N=1e2+10, K=1e4+10;
const int inf=1e9;

int a[N];
int f[2][N][K];

int main()
{
// freopen( "txt.in","r",stdin );
// freopen( "txt.out","w",stdout );
ios::sync_with_stdio( false );
cin.tie( nullptr ); cout.tie( nullptr );
int n, l, r, K;
cin>>n>>l>>r>>K;
for( int i=1;i<=n;i++ ) cin>>a[i];
int m=r-l+1;
memset( f,0x3f,sizeof f );
f[0][0][0]=0;
for( int i=1;i<=n;i++ ) for( int j=0;j<=m;j++ ) for( int k=0;k<=K;k++ )
{
int w=abs( l+j-i-1 );
f[i&1][j][k]=f[i&1^1][j][k];
if( k >= w && j >= 1 ) f[i&1][j][k]=min( f[i&1][j][k],f[i&1^1][j-1][k-w]+a[i] );
}
int ans=inf;
for( int i=0;i<=K;i++ ) ans=min( ans,f[n&1][m][i] );
cout<<ans;
QWQ
}