zoukankan      html  css  js  c++  java
  • [BZOJ] 2064: *

    注意到(n)很小,应该是状压DP

    记原集合为(S),目标集合为(T),如果我们能把(S)分成(x)个不相交的非空子集,且这(x)个子集能和(T)中的一些不相交非空子集的和相等,那么最终答案就是(n+m-2x),其中(n=|S|,m=|T|)

    因此我们要最大化(x),这就是DP的目标了

    (f[x][y])表示(S)的子集(x)(T)的子集(y)(sum)相等的最多能配几对

    (sum[x] ot=sum[y]),枚举删去(x)(y)的一个元素

    [f[x][y]=max{f[xoplus i][y],f[x][yoplus j]} ]

    (sum[x]=sum[y]),情况看起来复杂了

    为了转移,我们似乎要再枚举子集,复杂度不能接受

    但是这样想,既然(sum[x]=sum[y]),那么(x)(y)至少配成了一对,若在其中删去一个元素,一定会减少一对

    因此

    [f[x][y]=1+max{f[xoplus i][y],f[x][yoplus j]} ]

    这样省去了枚举子集,复杂度有保障

    最终复杂度(O((n+m)2^{n+m}))

    骚操作:如何统计(sum[x])

    以前一直写

    for(int S=0;S<(1<<n);S++)
        for(int i=0;i<n;i++)
            if(S&(1<<i))sum[S]+=a[i];
    

    这样做是(O(n2^n))的,实际上,完全可以省去一个(O(n)) (虽然(n)很小..)

    类似统计二进制中1的个数一样,可以复用(S)的子集,方法就是用lowbit

    也就是(sum[x]=sum[xoplus lowbit(x)]+sum[lowbit(x)])

    边界是(sum[1<<i]=a[i+1])

    这样是(O(2^n))

     
    #include<algorithm>
    #include<iostream>
    #include<cstdio>
     
    using namespace std;
     
    inline int rd(){
      int ret=0,f=1;char c;
      while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
      while(isdigit(c))ret=ret*10+c-'0',c=getchar();
      return ret*f;
    }
    #define space putchar(' ')
    #define nextline putchar('
    ')
    void _(int x){if(!x)return;_(x/10);putchar('0'+x%10);}
    void out(int x){if(!x)putchar('0');_(x);}
     
    const int MAXN = 10;
     
    inline void upmax(int &x,int y){x=max(x,y);}
     
    int a[MAXN],b[MAXN];
    int f[1<<MAXN][1<<MAXN];
    int sum1[1<<MAXN],sum2[1<<MAXN];
    int n,m;
     
    int main(){
      n=rd();
      for(int i=1;i<=n;i++)sum1[1<<(i-1)]=a[i]=rd();
      m=rd();
      for(int i=1;i<=m;i++)sum2[1<<(i-1)]=b[i]=rd();
      for(int i=1;i<(1<<n);i++){
        sum1[i]=sum1[i^(i&-i)]+sum1[i&-i];
      }
      for(int i=1;i<(1<<m);i++){
        sum2[i]=sum2[i^(i&-i)]+sum2[i&-i];
      }
      for(int s=1;s<(1<<n);s++){
        for(int t=1;t<(1<<m);t++){
          for(int i=0;i<n;i++){
            if(s&(1<<i)) upmax(f[s][t],f[s^(1<<i)][t]);
          }
          for(int i=0;i<m;i++){
            if(t&(1<<i)) upmax(f[s][t],f[s][t^(1<<i)]);
          }
          if(sum1[s]==sum2[t])f[s][t]++;
        }
      }
      cout<<n+m-2*f[(1<<n)-1][(1<<m)-1];
      return 0;
    }
    
    
    未经许可,禁止搬运。
  • 相关阅读:
    BZOJ5212 ZJOI2018历史(LCT)
    BZOJ5127 数据校验
    253. Meeting Rooms II
    311. Sparse Matrix Multiplication
    254. Factor Combinations
    250. Count Univalue Subtrees
    259. 3Sum Smaller
    156. Binary Tree Upside Down
    360. Sort Transformed Array
    348. Design Tic-Tac-Toe
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9802403.html
Copyright © 2011-2022 走看看