题目:http://acm.hdu.edu.cn/showproblem.php?pid=5330
题意:给出n个长度为m,并且只有012组成的串,两个串的距离为每一位相差的绝对值相加,问距离为0-2m的对数分别有几对
参考:http://blog.csdn.net/glqac/article/details/48971143
最后计算答案的时候,距离为0的话只能跟相同串的互相选择,不为零就是直接相乘
最后所有对数都算了两遍,所以要除2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
const int N=2e5+5;
int cnt[N],dp[2][N][25];
int f[20];
char s[20];
long long ans[25];
int now=0,pre=1;
int main()
{
f[0]=1;
for(int i=1;i<=11;i++)
f[i]=f[i-1]*3;
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
{
scanf("%s",s);
int sum=0;
for(int j=0;j<m;j++)
sum=sum*3+s[j]-'0';
cnt[sum]++;
}
memset(dp[now],0,sizeof(dp[now]));
for(int i=0;i<f[m];i++)
dp[now][i][0]=cnt[i];
for(int i=0;i<m;i++)
{
swap(now,pre);
memset(dp[now],0,sizeof(dp[now]));
for(int j=0;j<f[m];j++)
for(int k=0;k<=2*m;k++)
if (dp[pre][j][k])
{
int tem=j/f[i]%3;
for(int l=0;l<=2;l++)
{
int t=j-(tem-l)*f[i];
dp[now][t][k+abs(tem-l)]+=dp[pre][j][k];
}
}
}
memset(ans,0,sizeof(ans));
for(int i=0;i<f[m];i++)
{
if (!cnt[i]) continue;
ans[0]+=1LL*cnt[i]*(cnt[i]-1);//dp[now][i][0]==cnt[i]
for(int j=1;j<=2*m;j++)
ans[j]+=1LL*cnt[i]*dp[now][i][j];
}
for(int i=0;i<=2*m;i++)
printf("%lld\n",ans[i]/2LL);
}
return 0;
}