UOJ370 滑稽树上滑稽果 【状压DP】

题目分析:

答案肯定是链,否则可以把枝干放到主干。

去除一直存在的位,这样0位占满时就会结束。

用$f[S]$表示0位填埋情况,每次转移是它的一个子集,我们考虑可否转移。

再用$g[S]$存储转移是否合法,用滑稽果填充$g$数组。不一定要完全满足条件,因为有其它方案更优,无影响。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define RI register
 5 
 6 const int maxn = 202000;
 7 
 8 int n,a[maxn],bit=1,maxx;
 9 long long ans = 0;
10 int cnt = (1<<18)-1,res=0;
11 
12 int f[1<<18];
13 int g[1<<18],vol[1<<18];
14 char buffer[20000000], *buf=buffer;
15 inline void in(int &x) {
16     while(*buf>'9' || *buf<'0') ++buf;
17     for(x=0;*buf>='0'&&*buf<='9'; ++buf) x=x*10+*buf-'0';
18 }
19 
20 inline void read(){
21     in(n);
22     for(RI int i=1;i<=n;i++) in(a[i]),cnt &= a[i];
23     for(RI int i=1;i<=n;i++) a[i] -= cnt,maxx=max(maxx,a[i]),res |= a[i];
24     ans += 1ll*cnt*n;
25 }
26 
27 inline void init(){
28     while((bit<<1)<=maxx)bit<<=1; bit<<=1; res = (bit-1-res);
29     for(RI int i=1;i<=n;i++) vol[bit-1-a[i]]=1;
30     for(RI int i=bit-1;i>=0;i--){
31     if(!vol[i] || g[i]) continue;
32     for(RI int j=i;j;j=((j-1)&i)){g[j]=1;}
33     }
34 }
35 
36 inline void work(){
37     memset(f,0x3f,sizeof(f)); f[0] = 0;
38     for(RI int now=0;now<bit;now++){
39     if(f[now] > 1e6) continue;
40     int dt = bit-1-now;
41     for(RI int i=dt;i;i=((i-1)&dt)){
42         if(g[i]){f[now+i] = min(f[now+i],f[now]+bit-1-(now+i));};
43     }
44     }
45     ans += f[bit-1];
46     printf("%lld",ans);
47 }
48 
49 int main(){
50     fread(buffer, 1, (sizeof buffer)-1, stdin);
51     read();
52     init();
53     work();
54     return 0;
55 }

 

转载于:https://www.cnblogs.com/Menhera/p/9277639.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值