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]);
}