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;
} 
posted @ 2021-02-19 22:39  WWW~~~  阅读(194)  评论(0)    收藏  举报