首页 > 代码库 > ural 1932 The Secret of Identifier (容斥原理)

ural 1932 The Secret of Identifier (容斥原理)

题目大意:

求出给的n个串中。

精确到只有一个字符不同,两个字符不同,三个字符不同,四个字符不同的对数。


思路分析:

枚举状态。

dp[i] [j] ...表示当前串取出 i 状态下的所有字符转化成十进制数为 j 的出现的次数。

这样的话,就记录了所有串的子串的状态。

然后计数就得到了所有的状态。

然后我们要得到精确不同的,可以用补集的思想,如果要精确到三个不相同,意味着要精确到1 个是相同的。


注意的问题是

在最后要运用容斥去重。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
typedef long long ll;

char str[6];
ll dp[16][1<<16];

int trans(char ch)
{
    if(isdigit(ch))return ch-'0';
    return ch-'a'+10;
}
int Count(int x)
{
    int ret=0;
    while(x){
        ret+=(x&1);
        x>>=1;
    }
    return ret;
}
ll tmp[5],ans[5];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        int maxm=-1;
        memset(dp,0,sizeof dp);
        memset(tmp,0,sizeof tmp);

        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            for(int s=1;s<16;s++)
            {
                int t=0;
                if(s&8) t += trans(str[0])*(1<<12);
                if(s&4) t += trans(str[1])*(1<<8);
                if(s&2) t += trans(str[2])*(1<<4);
                if(s&1) t += trans(str[3]);
                dp[s][t]++;
                maxm=max(t,maxm);
            }
        }
        for(int s=1;s<16;s++)
        {
            int x=Count(s);
            for(int i=0;i<=maxm;i++)
            {
                tmp[x]+=dp[s][i]*(dp[s][i]-1)/2;
            }
        }

        ans[1]=tmp[3];
        ans[2]=tmp[2]-3*tmp[3];
        ans[3]=tmp[1]-2*tmp[2]+3*tmp[3];
        printf("%I64d %I64d %I64d %I64d\n",ans[1],ans[2],ans[3],(ll)n*(n-1)/2-ans[1]-ans[2]-ans[3]);
    }
    return 0;
}