【GDOI2016模拟3.10】习用之语

Description

有N个长度为4的字符串,求着N个字符串中有多少对差且仅相差d个字符。
N<=50000

Solution

对于这种差且仅相差的题目,一般都会用容斥原理。
首先,我们统计出,这N个字符串中,至少有L个字符相同的对数,设为F[l]。
那么答案G[]可以通过F容斥出来。
G[0]=F[4](显然)
G[1]=F[3]-4*G[0](仅为1个不同(即仅为3个相同),在仅为0个不同(即全部相同)里算了4次,这4次都要去掉,后面同理)
G[2]=F[2]-3*G[1]-6*G[0]
G[3]=F[1]-2*G[2]-3*G[1]-4*G[0]
G[4]=N*(N-1)/2-G[0]-G[1]-G[2]-G[3](这里用了比较取巧的方法,即用总的减去其他的)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define N 50005
#define P 37
using namespace std;
map<int,int> h[16];
ll f[5],g[5];
int c[5][5],s[N][5],n,ans,k;
char st[5];
bool bz[5];
void dfs(int x,int y) {
    if (x>3) {
        int cnt=0,id=0,sum=0,tot=0,z=1;
        fo(i,0,3) if (bz[i]) cnt=cnt*P+s[y][i],id+=1<<i,tot++;
        f[tot]+=h[id][cnt];
        h[id][cnt]++;
        return;
    }
    bz[x]=1;dfs(x+1,y);bz[x]=0;dfs(x+1,y);
}
int main() {
    scanf("%d%d",&n,&k);
    fo(i,1,n) {
        scanf("%s",st);
        fo(j,0,3) {
            if (st[j]<='9') s[i][j]=st[j]-'0'+1;
            else s[i][j]=st[j]-'a'+11;
        }
    }
    fo(i,0,4) c[i][0]=1;
    fo(i,1,4)
        fo(j,1,i)
            c[i][j]=c[i-1][j]+c[i-1][j-1];
    fo(i,1,n) dfs(0,i);
    g[0]=f[4];
    g[1]=f[3]-g[0]*4;
    g[2]=f[2]-g[1]*3-g[0]*6;
    g[3]=f[1]-g[2]*2-g[1]*3-g[0]*4;
    g[4]=(ll)n*(n-1)/2-g[0]-g[1]-g[2]-g[3];
    printf("%lld",g[k]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值