【题解】P6521 [CEOI 2010] pin (day2)
P6521 [CEOI 2010] pin (day2)
题意
给定 \(n\) 个长度为 \(4\) 的字符串,求出有多少对字符串满足恰好 \(D\) 个对应位置的字符不同。
题解
知识点:二项式反演,组合数学。
启发:
- 枚举匹配状态计算 \(f\) 函数。
令 \(d\leftarrow 4-d\),那么求的就变成了恰好 \(d\) 个对应位置的字符相同的对数。
设 \(g_m\) 为恰好有 \(m\) 个位置相同的对数。
设 \(f_m\) 为钦定 \(m\) 个位置相同,其余随意的对数。
所以会满足,
\[\large \displaystyle f_m=\sum_{i=m}^4 \binom{i}{m} \times g_i
\]
二项式反演得到,
\[\large \displaystyle g_m=\sum_{i=m}^4 \binom{i}{m} \times (-1)^{i-m} f_i
\]
这题的 \(f_m\) 没有固定的式子,不过字符串长度很小,可以枚举 \(s\in [0,15]\) 表示四个位的状态,每次扫一遍,只关心为 \(1\) 的位置上的字符,做一遍哈希,对哈希值相同的两两组合计入 \(res\),最后累加到 \(f_{\operatorname{popcount(s)}}\) 即可。
答案即为 \(g_d\)。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 202504
#define int long long
int n,d,f[N],C[10][10];
string a[N];
inline int pcnt(int x){
int ans=0;
while(x){
ans+=x&1;
x>>=1;
}
return ans;
}
inline void init(int lim){
rep(i,0,lim){
C[i][0]=1;
}
rep(i,1,lim){
rep(j,1,i){
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
}
inline int neg(int x){
return x&1?-1:1;
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>d;
d=4-d;
rep(i,1,n){
cin>>a[i];
}
rep(s,0,15){
unordered_map<int,int>mp;
rep(i,1,n){
int ha=0;
rep(j,0,3){
if(!((s>>j)&1)){
continue;
}
ha=ha*131+a[i][j];
}
mp[ha]++;
}
int p=pcnt(s);
for(auto x:mp){
f[p]+=x.se*(x.se-1)/2;
}
}
init(4);
int ans=0;
rep(i,d,4){
ans+=C[i][d]*neg(i-d)*f[i];
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号