感觉这种dp和子集和dp差不多, 有点难想到。
dp[ i ][ S ][ j ] 表示最低的 i 位和 S最低的 i 位一样的所有串中, 和 S 的距离为 j 的有多少个。
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 2e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = (int)1e9 + 7; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T &a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T &a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T &a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T &a, S b) {return a > b ? a = b, true : false;} mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); int n, m, up; int dp[2][N][23]; int c[N]; int (*f)[23] = dp[0]; int (*g)[23] = dp[1]; int v[12]; LL ans[23]; char s[20]; void init() { memset(ans, 0, sizeof(ans)); for(int i = 0; i < up; i++) { c[i] = 0; } for(int i = 0; i < up; i++) { for(int j = 0; j <= 2 * m; j++) { f[i][j] = 0; } } } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &m); up = 1; for(int i = 1; i <= m; i++) { up = up * 3; } init(); for(int i = 0; i < n; i++) { int val = 0; scanf("%s", s); for(int j = 0; j < m; j++) { val = val * 3 + (s[j] - '0'); } f[val][0]++; c[val]++; } for(int i = 0; i < m; i++) { swap(f, g); for(int mask = 0; mask < up; mask++) { for(int j = 0, k = mask; j < m; j++, k /= 3) { v[j] = k % 3; } int pmask0 = 0, pmask1 = 0, pmask2 = 0; for(int j = m - 1; j >= 0; j--) { pmask0 *= 3; pmask1 *= 3; pmask2 *= 3; if(j == i) { pmask0 += 0; pmask1 += 1; pmask2 += 2; } else { pmask0 += v[j]; pmask1 += v[j]; pmask2 += v[j]; } } for(int j = 0; j <= 2 * m; j++) { f[mask][j] = 0; if(v[i] == 0) { f[mask][j] += g[pmask0][j]; if(j >= 1) f[mask][j] += g[pmask1][j - 1]; if(j >= 2) f[mask][j] += g[pmask2][j - 2]; } else if(v[i] == 1) { if(j >= 1) f[mask][j] += g[pmask0][j - 1]; f[mask][j] += g[pmask1][j]; if(j >= 1) f[mask][j] += g[pmask2][j - 1]; } else { if(j >= 2) f[mask][j] += g[pmask0][j - 2]; if(j >= 1) f[mask][j] += g[pmask1][j - 1]; f[mask][j] += g[pmask2][j]; } } } } for(int mask = 0; mask < up; mask++) { ans[0] += 1LL * c[mask] * (c[mask] - 1); for(int j = 1; j <= 2 * m; j++) { ans[j] += 1LL * c[mask] * f[mask][j]; } } for(int i = 0; i <= 2 * m; i++) { printf("%lld\n", ans[i] / 2); } } return 0; } /* */