SOS DP/Gym - 102576B

SOS DP/Gym - 102576B 
我看懂了!!
契机:排位赛B题,愣是不会求,😭
Sum over subsets -> SOS
比如这样一个问题:给你一个长度为n的数组,然后统计有多少个数对 (a[i]&a[j])==a[i];
把a[j]化为2进制 100010101, 那也就是找出满足 a[j]对应位置为1,a[i]可以为1也可以为0,a[j]对应位置为0,a[i]只能为0
条件的a[i]

定义s[mask,i]表示,从右向左,从0开始,只能前i位和mask不同的个数

例子:

 

 


如果mask的第i位为0,那么s[mask,i]=s[mask,i-1]
如果mask的第i位为1,那么s[mask,i]=s[mask,i-1]+s[mask^(1<<i),i-1]

 

 

 

时空间优化:第二维度可以省略

 

#include <bits/stdc++.h>
#define inf 2333333333333333
#define N 1100010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
//by war
//2020.9.28
using namespace std;
long long T,n,ans;
long long s[N],cnt[N],a[N];
void in(long long &x){
    long long y=1;char c=getchar();x=0;
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    x*=y;
}
void o(long long x){
    if(x<0){p('-');x=-x;}
    if(x>9)o(x/10);
    p(x%10+'0');
}

signed main(){
    in(T);
    while(T--){
        in(n);
        For(i,1,n){
            in(a[i]);
            cnt[a[i]]++;
        }
        For(i,1,n) s[a[i]]=cnt[a[i]];
        For(i,0,20){
            For(j,0,(1<<20)){
                if(j&(1<<i)){
                    s[j]+=s[j^(1<<i)];
                }
            }
        }
        ans=0;
        For(i,1,n) ans+=s[a[i]];
        o(ans);p('\n');
        For(i,1,n) cnt[a[i]]=0;
        memset(s,0,sizeof s);
    }
    return 0;
}

 

posted @ 2020-09-28 13:07  WeiAR  阅读(184)  评论(0编辑  收藏  举报