数位DP::SoSDP

数位DP:: SoSDP

学习博客(待补)

下面做一些例题:

SPECIAL PAIRS

题意

给n个数字,求这些数字有多少对的(AND) 结果是0。数字不大于1e6。顺序反相反视为不同的对。

思路

做一个桶排计数。对于每个数(a_i) ,与他(AND) 是0的数,就是反$ a_i$ 的子集。也即是SoSDP里的F所统计的量了。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e6+5;;
int a[MAXN];
int x[MAXN];
long long dp[MAXN];
int kase,n;

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>kase;
    while(kase--){
        cin>>n;
        memset(a,0,sizeof a);
        memset(dp,0,sizeof dp);

        for(int i=1;i<=n;i++){
            cin>>x[i];
            dp[x[i]]=++a[x[i]];
        }
        for(int i=0;i<=20;i++)
        for(int mask=0;mask<=(1<<20);mask++){
            if(mask&(1<<i)){
                dp[mask]+=dp[mask^(1<<i)];
            }
        }
        int mask=(1<<20)-1;
        long long ans=0;
        for(int i=1;i<=n;i++){
            ans+=dp[(~x[i])&mask];
        }
        cout<<ans<<endl;
    }
    return 0;
}
/*
4
5
41 47 34 40 29
4
999956 999959 999993 999993
3
4 1 3
3
1 0 0e
*/

注意几个细节:

位数一定取到最大值的长度(假设是len),而答案要记录到((1)_B^{len}) 。我一开始答案只记录到最大值,导致一部分漏解了。

简化代码的写法就是每次都走到数据范围最大的解答,为了更加优化可以去找一下最大值作为边界。

原文地址:https://www.cnblogs.com/tieway59/p/10785560.html