Bzoj4069:[Apio2015]巴厘島的雕塑:dp+貪心

題目鏈接:[Apio2015]巴厘島的雕塑

一開始先寫了個既錯誤又高複雜度的dp,令dp[i][j]=min(dp[i][k],dp[j][k-1]|(s[i]-s[j])),其中s[]代表前綴和

首先超時不說,在或的情況下單純地每步取最小值無法保證全局的最優性,但是即使是這樣我還是奇奇怪怪的過了好幾個點QAQ

正解是這樣的:

首先處理出答案最多的可能位數bit,然後倒序從最高位開始枚舉每一位,由於∑2^i(0<i<n)<2^n+1,所以當前這一位能不選就不選

設dp[i][j]表示前i個數分成了j組並且滿足已經枚舉完的k位是否可行,可行爲1否則爲0

設當前最高的k位貢獻的最小答案爲ans,那麼dp[i][j]=1當且僅當dp[k][j-1]==1&&((s[i]-s[k])>>(k+1+1))|ans)==ans&&((s[i]-s[k])>>(k+1)&1==0),即滿足已經得到的最優答案並且當前枚舉到得這一位爲0,複雜度O(n^3)

但是發現a==1的時候我們就沒有必要枚舉分成了幾段,設dp[i]表示前i個數滿足要求的情況下最少分成幾段然後和b比較判斷可行性即可

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define rep(i,x,y) for (int i=x;i<=y;++i)
#define dow(i,x,y) for (int i=x;i>=y;--i)
using namespace std;
const int maxn=2010;
const LL inf=1e16;
int n,a,b,f[maxn];
bool dp[maxn][maxn];
LL s[maxn];

bool check(int bit,LL x,LL tmp){
	return (((x>>(bit+1))|tmp)==tmp&&((x>>bit)&1)==0);
}

void solve1(int bit){
	LL ans=0;
	for (int d=bit;d>=0;d--){
		rep(i,1,n) {
			f[i]=n+1; rep(j,0,i-1){
				if (check(d,s[i]-s[j],ans)&&f[i]>f[j]+1)
				    f[i]=f[j]+1;
			}
		}ans=ans<<1|(f[n]>b);
	}printf("%lld",ans);
}

void solve2(int bit){
	LL ans=0;
	for (int d=bit;d>=0;d--){
		dp[0][0]=1;
		rep(i,1,n) rep(j,1,min(i,b)){
			dp[i][j]=0;
			for (int k=0;k<i&&!dp[i][j];k++)
			    if (dp[k][j-1]&&check(d,s[i]-s[k],ans))
			        dp[i][j]=1;
		}
		int tmp=1;
		for (int i=a;i<=b;++i)
		    if (dp[n][i]){tmp=0;break;}
		ans=ans<<1|tmp;
	}printf("%lld",ans);
}

int main(){
	scanf("%d%d%d",&n,&a,&b);
	rep(i,1,n) {LL x;scanf("%lld",&x);s[i]=s[i-1]+x;}
	int bit=0; while ((1LL<<bit)<s[n]) bit++;
	if (a==1)solve1(bit); else solve2(bit);
}


發佈了112 篇原創文章 · 獲贊 12 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章