单词
小y有n个长度为m,且只含x,y,z的单词,给定相似度的定义:两个单词相同位相同的字母数
d=∑[Ai==Bi]
求相似度为0~m的单词对有多少个
注意:(x,y)=(y,x)不考虑(x,x)
输入:
n m
n个长度为m的单词
输出:
m+1行
第i行表示相似度为i-1时,单词对数
样列输入:
4 3
xyz
xyz
zzx
xzz
输出:
2
1
2
1
范围:n*m<=100000
(分类讨论)暴力+dp
n*m<=100000所以n大m就小,m大n就小
m>=12时,n小直接枚举区间暴力判断
m<=12时,我们用状压dp
用0表示x,1表示y,2表示z
用3进制数表示
f[s][p]表示状态为s,相似度为p的对数
每一次修改状态中一个数
f[s'][p-1]+=f[s][p];
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 typedef long long ll; 7 ll pw[15],f[550001][13],ff[550001][13],ans[100001]; 8 ll s[550001]; 9 int n,m; 10 char str[100001]; 11 void work1() 12 {int i,j,p,l; 13 for (i=1; i<=n; i++) 14 {int now=0; 15 for (j=1; j<=m; j++) 16 { 17 now*=3; 18 char ch=getchar(); 19 while (ch<'x'||ch>'z') ch=getchar(); 20 now+=ch-'x'; 21 } 22 s[now]++; 23 } 24 pw[0]=1; 25 for (i=1;i<=m;i++) pw[i]=pw[i-1]*3; 26 for (i=0;i<pw[m];i++) ff[i][m]=s[i]; 27 for (i=0;i<m;i++) 28 {memcpy(f,ff,sizeof(f)); 29 for (j=0;j<pw[m];j++) 30 { 31 ll s1=j/pw[i]%3,s2=j-s1*pw[i]; 32 for (p=0;p<=2;p++) 33 if (p!=s1) 34 { 35 for (l=m-i;l<=m;l++) f[s2+p*pw[i]][l-1]+=ff[j][l]; 36 } 37 } 38 memcpy(ff,f,sizeof(f)); 39 } 40 for (i=0;i<pw[m];i++) 41 { 42 for (j=0;j<=m;j++) 43 ans[j]+=s[i]*ff[i][j]; 44 } 45 ans[m]-=n; 46 for (i=0;i<=m;i++) ans[i]/=2; 47 } 48 void work2() 49 {int i,j,l; 50 for (i=0; i<n*m; i++) 51 { 52 char ch=getchar(); 53 while (ch<'x'||ch>'z') ch=getchar(); 54 str[i]=ch; 55 } 56 for (i=0; i<n; i++) 57 for (j=0; j<i; j++) 58 { 59 int cnt=0; 60 for (l=0; l<m; l++) 61 if (str[i*m+l]==str[j*m+l]) 62 cnt++; 63 ans[cnt]++; 64 } 65 } 66 int main() 67 {int i; 68 cin>>n>>m; 69 if (m<=12) work1(); 70 else work2(); 71 for (i=0; i<=m; i++) 72 printf("%lld\n",ans[i]); 73 }