Description
Input
输入的第一行包含三个用空格分开的整数 N,A,B。
Output
输出一行一个数,表示最小的最终优美度。
Sample Input
8 1 2 1 5 4
Sample Output
explanation
将这些雕塑分为 2 组,(8,1,2) 和 (1,5,4),它们的和是 (11) 和 (10),最终优美度是 (11 OR 10)=11。(不难验证,这也是最终优美度的最小值。)
HINT
子任务 1 (9 分)
题解:考虑按位贪心来做。从高到低枚举答案的每一位,对于当前位,我们先check一下当前位=0能否满足要求,如果可以,则当前位=0,否则=1。那么如何check呢?考虑DP,用f[i][j]表示前i个雕塑分成j组是否可行,如果要求当前位=0可以满足要求,那么就把所有可能使得当前位!=0的转移都打上删除标记即可。
但是这样的转移时O(n^3)的啊,于是看了题解。。。md你告诉我最后一个子任务A=1!!!那么直接将DP方程该为f[i]表示将前i个雕塑最少能分成几组,然后转移就是O(n^2)的了。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; int n,A,B; bool f[2][110],mp[2010][2010]; int g[2010]; ll ans,s[2010]; bool check(ll v) { if(v<=8) { v++,v--; } int i,j,k,d; if(A==1) { memset(g,0x3f,sizeof(g)),g[0]=0; for(i=1;i<=n;i++) for(j=0;j<i;j++) if(!mp[i][j]&&!((s[i]-s[j])&v)) g[i]=min(g[i],g[j]+1); return g[n]<=B; } memset(f[0],0,sizeof(f[0])); f[0][0]=1; for(i=1;i<=B;i++) { d=i&1; memset(f[d],0,sizeof(f[d])); for(j=1;j<=n;j++) for(k=0;k<j;k++) if(!mp[j][k]&&!((s[j]-s[k])&v)) f[d][j]|=f[d^1][k]; if(i>=A&&f[d][n]) return 1; } return 0; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } int main() { scanf("%d%d%d",&n,&A,&B); int i,j; for(i=1;i<=n;i++) s[i]=rd()+s[i-1]; for(ll k=1ll<<40;k;k>>=1) { if(check(k)) { for(i=1;i<=n;i++) for(j=0;j<i;j++) if((s[i]-s[j])&k) mp[i][j]=1; } else ans|=k; } printf("%lld",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<