把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P3646 [APIO2015]巴厘岛的雕塑

题面传送门
这个题很屑啊强行套两个题上去。
首先肯定要从高到低枚举位然后看这一位是否可以为\(1\)
然后问题转化为判定能否分成\(i,i\in[A,B]\)段,且或的值是一个给定数的子集,这个东西可以\(O(n^3)\)的dp解决掉。
具体的,设\(f_{i,j}\)为分了\(j\)段,到了第\(i\)个数的方案数,转移的时候这一段的值一定是\(d\)的子集。
这个是\(O(n^3logW)\)的可以拿前四个包。
考虑到最后一个点\(A=1\),那么直接记最小值转移就好了。时间复杂度\(O(n^2logW)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define lb long db
#define N 2000
#define W (1<<31)-1
#define mod 998244353
#define Mod 998244352
#define eps (1e-4)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Pc(x) putchar(x) 
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int dp[N+5],Q[N+5],n,A,B;ll S[N+5],D;vector<int> Id[N+5];
I int check1(ll d){
	re int i,j,h;for(i=1;i<=n;i++) for(Id[i].clear(),j=0;j<i;j++) (((S[i]-S[j])|d)==d)&&(Id[i].push_back(j),0);Me(Q,0);Q[0]=1;
	for(i=1;i<=B;i++){
		Me(dp,0);for(j=1;j<=n;j++){
			for(h=0;h<Id[j].size();h++) if(Q[Id[j][h]]){dp[j]=1;break;}
		}if(i>=A&&dp[n]) return 1;memcpy(Q,dp,sizeof(Q));
	}return 0;
}
I int check2(ll d){
	re int i,j;Me(dp,0x3f);dp[0]=0;for(i=1;i<=n;i++){
		for(j=0;j<i;j++) (((S[i]-S[j])|d)==d)&&(dp[i]=min(dp[i],dp[j]+1));
	}return dp[n]<=B;
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d%d%d",&n,&A,&B);for(i=1;i<=n;i++) scanf("%lld",&S[i]),S[i]+=S[i-1];for(i=42;~i;i--)D+=1ll*((A==1)?!check2(D+(1ll<<i)-1):!check1(D+(1ll<<i)-1))<<i;printf("%lld\n",D);
}
posted @ 2021-08-23 10:00  275307894a  阅读(31)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end