题目

低智选手果然刷不动uoj

首先考虑一下构造一棵树显然是骗你玩的,按位与这个东西越做越小,挂到链的最下面显然不会劣于挂到之前的某一个点下面,所以我们只需要求一个排列使得答案最小就好了

设\(A=\max(a_i)\),发现最优答案不可能要劣于反复对一个数取\(\rm and\)的答案,我们就有了一个\(O(nA)\)的暴力,设\(dp_i\)表示当前的\(\rm and\)和为\(i\),把这个\(i\)变成\(0\)的最小代价

但是有可能最后的\(\rm and\)和也不是\(0\),于是我们把所有\(a_i\)都共有的二进制位\(k\)都求出来,在把每一个\(a_i\)消去这些数位,即和\(k\)异或一下,最后的\(\rm and\)和就一定为\(0\);在答案加上\(n\times k\)就好了

这样的话转移非常简单,我们枚举一个\(a_j\),\(dp_i=\min(dp_{i\ \rm and \ a_j }+i\ \rm and \ a_j)\)即可

最后答案是\(\min(dp_{a_i}+a_i)\)

注意到\(i\ \rm and \ a_j\)一定是\(i\)的子集,考虑枚举\(i\)的子集\(j\),现在只需要判断是否存在一个\(a_k\)满足\(i\ \rm and\ \ a_k=j\)

从集合的角度来考虑,我们可以把上面那个条件拆成\(j\)是\(a_k\)的子集,并且\(a_k\)是\(j\bigoplus i\)在全集补集中的子集,我们用\(\rm fwt\)处理一下就可以知道是否有一个\(a_k\)是\(i\bigoplus j\)在全集补集中的子集,但并没有办法判断\(j\)是否为\(a_k\)的子集

但是想一想发现我们没有必要判断\(j\)是否为\(a_k\)的子集,只管转移就好了

观察转移式\(dp_i=\min(dp_j+j)\),显然\(j\)越小越好,如过存在\(a_k\)是\(i\bigoplus j\)在全集补集中的子集,但是\(a_k\)并不是\(j\)的子集,那么一定会有一个更小的\(i\)的子集是这个\(a_k\)的子集,那个转移一定更优

于是复杂度就是\(O(3^{\log A})\)

  1. #include<bits/stdc++.h>
  2. #define re register
  3. #define LL long long
  4. #define min(a,b) ((a)<(b)?(a):(b))
  5. #define max(a,b) ((a)>(b)?(a):(b))
  6. inline int read() {
  7. char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
  8. while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
  9. }
  10. const int maxn=1e5+5;
  11. int n,a[maxn],vis[1<<18+1],k,T,len;
  12. LL dp[1<<18+1],ans;
  13. int main() {
  14. n=read();
  15. for(re int i=1;i<=n;i++) a[i]=read(),T=max(T,a[i]);
  16. len=1;while(len<T) len<<=1;len--;
  17. for(re int i=1;i<=n;i++) vis[a[i]]=1;
  18. for(re int i=2;i<=len+1;i<<=1)
  19. for(re int ln=i>>1,l=0;l<len;l+=i)
  20. for(re int x=l;x<l+ln;++x) vis[x+ln]|=vis[x];
  21. k=a[1];for(re int i=2;i<=n;i++) k&=a[i];
  22. for(re int i=1;i<=n;i++) a[i]^=k;
  23. memset(dp,20,sizeof(dp));
  24. ans=dp[0];dp[0]=0;
  25. for(re int i=1;i<=T;i++)
  26. for(re int j=i;j;j=(j-1)&i)
  27. if(vis[len^j]&&dp[i^j]+(i^j)<dp[i]) dp[i]=dp[i^j]+(i^j);
  28. for(re int i=1;i<=n;i++)
  29. ans=min(ans,dp[a[i]]+a[i]);
  30. printf("%lld\n",1ll*n*k+ans);
  31. return 0;
  32. }

uoj#370【UR #17】滑稽树上滑稽果的更多相关文章

  1. U68464 滑稽树上滑稽果(guo)

    U68464 滑稽树上滑稽果(guo) 题目描述 小小迪有 n 个约会对象,每个对象有一个约会时长 p[i],小小迪 想尽可能多的去完成他的约会(假设小小迪可以瞬移),每个对象还有 一个忍耐时间 q[ ...

  2. UOJ#370. 【UR #17】滑稽树上滑稽果 动态规划

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ370.html 题解 首先易知答案肯定是一条链,因为挂在链的最下面肯定比挂在其他节点上赚. 问题被转化成了从一个集合中不断 ...

  3. UOJ#370. 【UR #17】滑稽树上滑稽果

    $n \leq 1e5$个点,每个点有个权值$a_i \leq 2e5$.现将点连成树,每个点$i$的链接代价为$a_i \ \ and \ \ i父亲的代价$,这里的$and$是二进制按位与,求最小 ...

  4. 【做题】uoj#370滑稽树上滑稽果——巧妙dp

    一个显然的结论是最终树的形态必然是一条链.具体证明只要考虑选定树上的某一条链,然后把其他部分全部接在它后面,这样答案一定不会变劣. 那么,一开始的想法是考虑每一位的最后出现位置,但这并不容易实现.注意 ...

  5. A. 【UR #17】滑稽树上滑稽果

    题解: 首先很显然的是这是一条链(特殊数据说是链是故意让人迷茫的??) 然后 自己就开始yy 觉得每一次是加入一个使得当前值最小的数 然而这tm又是特殊数据?? 那就写一波发现是错的 考虑一下特殊数据 ...

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

    题目分析: 答案肯定是链,否则可以把枝干放到主干. 去除一直存在的位,这样0位占满时就会结束. 用$f[S]$表示0位填埋情况,每次转移是它的一个子集,我们考虑可否转移. 再用$g[S]$存储转移是否 ...

  7. 吉首大学2019年程序设计竞赛(重现赛)I 滑稽树上滑稽果 (莫队+逆元打表)

    链接:https://ac.nowcoder.com/acm/contest/992/I来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒空间限制:C/C++ 32768K,其他语言65536K  ...

  8. 吉首大学校赛 I 滑稽树上滑稽果 (Lucas + 莫队)

    链接:https://ac.nowcoder.com/acm/contest/925/I来源:牛客网 题目描述 n个不同的滑稽果中,每个滑稽果可取可不取,从所有方案数中选取一种,求选取的方案中滑稽果个 ...

  9. 【UOJ#33】【UR#2】树上GCD 有根树点分治 + 容斥原理 + 分块

    #33. [UR #2]树上GCD 有一棵$n$个结点的有根树$T$.结点编号为$1…n$,其中根结点为$1$. 树上每条边的长度为$1$.我们用$d(x,y)$表示结点$x,y$在树上的距离,$LC ...

随机推荐

  1. Kotlin Doc

    { https://www.runoob.com/kotlin/kotlin-eclipse-setup.html }

  2. bzoj1016题解

    [解题思路] Kruskal的拓展. 可以先对边排序,进行一次Kruskal,判断是否可行,并计算出每种权值的边需要多少条. 然后暴力统计每种权值可行的方案数,根据乘法原理乘起来即可.复杂度o(210 ...

  3. NTT数论变换

    数论变换NTT 前置知识 FFT:NTT的思想和FFT一样(FFT介绍) 概述 数论变换,即NTT(Number Theory Transformation?),是基于数论域的FFT,一般我们默认FF ...

  4. KdPrint/DbgPrint and UNICODE_STRING/ANSI_STRING

    typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING ...

  5. 剑指offer——04从尾到头打印链表

    题目描述 输入一个链表,按链表从尾到头的顺序返回一个ArrayList.   有多种方法. class Solution { public: vector<int> printListFr ...

  6. jdbc出现中文乱码的解决办法

  7. 使用雪碧图Css Sprite精灵 | 加速网页响应速度

    什么是CSS Sprite精灵? 是用于前端的一种图片应用技术,通常情况,我们的开发的网页或许有很多张图片,假如在一个页面上有50多张小图片,这意味着浏览器要逐个下载50张图片.Css Sprite它 ...

  8. item字母问题

    解决方法:复写toString方法 @Override public String toString() { return this.getBookTypeName(); } 将对象的toString ...

  9. Swaks伪造邮件

    一.搭建邮件服务器 首先需要自己搭建邮件服务器采用的是EwoMail搭建参考链接: http://doc.ewomail.com/docs/ewomail/install 二.邮件伪造发送 swaks ...

  10. ionic js ion-tabs选项卡栏操作

    ionic 选项卡栏操作 ion-tabs ion-tabs 是有一组页面选项卡组成的选项卡栏.可以通过点击选项来切换页面. 对于 iOS,它会出现在屏幕的底部,Android会出现在屏幕的顶部(导航 ...