K. Bookcase Solidity United — Grand Prix of Belarus 题解+证明
K. Bookcase Solidity United — Grand Prix of Belarus — XXI Open Cup named after E.V. Pankratiev (yandex.ru) 题解
statement:

\(dp_{i,j,k}\)表示消除\([i,j]\)的架子,然后掉下来\(k\)个的答案。
转移不想多讲。
主要证明一下,最优情况下\(k\le \max\{a_i\}\),这样就可以保证时间复杂度为\(O(N^3M^2)\)了。
proof:
可以发现这些ball是一组一组掉的(转移的时候也用到了这个特性)
事实上只有一些组是有贡献的(打通一些架子)
其实只需要证明最优解转移下每一组的大小\(\le\max\{a_i\}\)就ok了。
事实上证明这个非常简单,观察球的下落就可以了。
是一些组掉到一个架子上,当前的球总数\(< a_i\),然后又突然掉下来一个大的是的总数\(\geq a_i\),然后架子坏掉,总数\(/2\)掉下来,可以发现我们甚至可以证明最优解下\(k\le \max\{a_i\}-1\)
code:
/*
Author Gary
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
// int x=0;
// char ch=getchar();
// while(ch<'0'||ch>'9'){
// ch=getchar();
// }
// while(ch>='0'&&ch<='9'){
// x=(x<<1)+(x<<3)+(ch^48);
// ch=getchar();
// }
// return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=71;
const int MAXAI=155;
int dp[MAXN][MAXN][MAXAI];
int n,a[1000];
int main(){
scanf("%d",&n);
int maxai=0;
rb(i,1,n){
scanf("%d",&a[i]);
check_max(maxai,a[i]);
}
maxai--;
memset(dp,63,sizeof(dp));
rb(i,1,n){
dp[i][i][a[i]/2]=a[i];
}
rb(len,2,n){
rb(l,1,n-len+1){
int r=len+l-1;
rb(j,a[r]/2,maxai){
int & ret=dp[l][r][j];
ret=INF;
rb(mid,l+1,r-1){
rb(k,a[r-1]/2,maxai){
int need=max(0,a[r]-k);
int K=k+need;//j-max(a[r],k)/2>=0,max(a[r],k)/2<=j
int l_=j-K/2;
if(l_>=0){
if(l_>=a[mid-1]/2){
check_min(ret,dp[mid][r-1][k]+dp[l][mid-1][l_]+need);
}
}
else break;
}
}
if(j==a[r]/2){
rb(k,a[r-1]/2,min(maxai,a[r]+1)){
int need=max(0,a[r]-k);
if((need+k)/2!=a[r]/2) break;
if(need<ret)
check_min(ret,dp[l][r-1][k]+need);
}
}
rb(k,a[r-1]/2,maxai){
if(k/2>j) break;
int l_=j*2-k;
check_max(l_,0);
if(l_+k>=a[r]&&l_<ret)
check_min(ret,dp[l][r-1][k]+l_);
}
check_min(ret,dp[l][r-1][j-a[r]/2]+a[r]);
}
}
}
rb(i,1,n){
int rest=INF;
rb(j,a[i]/2,maxai){
check_min(rest,dp[1][i][j]);
}
printf("%d ",rest);
}
return 0;
}

浙公网安备 33010602011771号