dp uoj370 滑稽树上滑稽果

Posted foreverpiano

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dp uoj370 滑稽树上滑稽果相关的知识,希望对你有一定的参考价值。

http://uoj.ac/problem/370

首先糊一个结论 答案组成的肯定是一条链

并且我们一定要用最小的代价把他先变成\(0\)

定义一个状态\(f[S]\)表示当前的滑稽值为\(S\)的最小费用

\[f[S] -> f[S \& a[i]] + S \& a[i]\]

此时复杂度为\(O(na)\)

观察发现转移的顺序与\(a_i\)是无关的

因为他是\(\&\) 起来的 费用就是原先数位上的\(1\)

于是我们就有一个想法

定义状态\(ok[S]\)表示\(S\)可以被某一个\(a_i\)变成0

然后转移就是看某一个\(S\)的子集是否能被变成\(0\)

复杂度挺鬼畜的\(O(a^{log_2 3}) = O(a^{1.58})\)

#include<bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int N = 3e5 + 233;
int Max = (1 << 18) - 1, n;
int a[N], f[N], has[N];

main(void) {
  read(n);
  int t = Max;
  memset(f, 38, sizeof f);
  for(int i = 1; i <= n; i ++)
    read(a[i]), t &= a[i];
  for(int i = 1; i <= n; i ++)
    a[i] ^= t, f[a[i]] = a[i];
  for(int k = 1; k <= n; k ++) {
    int st = Max ^ a[k];
    if(has[st]) continue;
    for(int i = st; i; i = (i - 1) & st)
      has[i] = 1;
  }
  for(int st = Max; st >= 1; st --)
    if(f[st] < f[0])
      for(int i = st; i; i = (i - 1) & st)
        if(has[i]) 
          f[st ^ i] = min(f[st ^ i], f[st] + (i ^ st));
  cout << t * n + f[0] << "\n";
}

以上是关于dp uoj370 滑稽树上滑稽果的主要内容,如果未能解决你的问题,请参考以下文章

做题uoj#370滑稽树上滑稽果——巧妙dp

uoj#370UR #17滑稽树上滑稽果

U68464 滑稽树上滑稽果(guo)

Test on 09/04/2016

题解 滑稽树前做游戏,滑稽树后做交易 trade

CF492E Vanya and Field