[CEOI2010 day2] pin
[CEOI2010 day2] pin
题目信息
题目链接
题目描述
给定 \(n\) 个长度为 \(4\) 的字符串,你需要找出有多少对字符串满足恰好 \(D\) 个对应位置的字符不同。
输入格式
输入第一行两个整数 \(n,D\)。
接下来的 \(n\) 行,每行一个长度为 \(4\) 的字符串。
输出格式
输出一行一个整数,表示满足条件的字符串的对数。
样例 #1
样例输入 #1
4 1
0000
a010
0202
a0e2
样例输出 #1
0
样例 #2
样例输入 #2
4 2
0000
a010
0202
a0e2
样例输出 #2
3
样例解释
样例 1 解释
任意两个字符串都有多于一个位置不相同。
样例 2 解释
共有三对字符串:0000,a010
a010,a0e2
0000,0202
。
数据规模与约定
- 对于 \(15\%\) 的数据,保证 \(n\le 2000\);
- 对于 \(30\%\) 的数据,保证 \(D=1\);
- 对于 \(60\%\) 的数据,保证 \(D\le 2\);
- 对于 \(75\%\) 的数据,保证字符串中只包含小写字母 \(a\sim f\) 以及数字。因此可以视为 \(16\) 进制数;
- 对于 \(100\%\) 的数据,保证 \(2\le n\le 5\times 10^4\),\(1\le D\le 4\),所有输入的字符串没有重复,串中的字符仅可能为 \(a\sim z\) 或者数字字符。
说明
思路分析
恰好有 \(D\) 个位置不同,可以考虑广义容斥原理。
用 \(g(S)\) 代表至少 \(S\) 位置集合中相同的对数。
用 \(f(S)\) 代表恰好 \(S\) 位置集合中相同的对数。
显然
\[g(S)=\sum_{T\supseteq S}{f(T)}
\]
根据广义容斥原理
\[f(S)=\sum_{T\supseteq S}{(-1)^{|S|-|T|}g(T)}
\]
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 5e4+10;
namespace math{
int frac[MAXN];
int qpow(int a,int b){
if(b==0) return 1;
if(b==1) return a;
int k = qpow(a,b>>1);
k*=k;
if(b&1) k*=a;
return k;
}
int C(int n,int m){
if(n<m) return 0;
return frac[n]/(frac[m]*frac[n-m]);
}
int get(int n,int m){
return C(m+n-1,m);
}
int lowbit(int k){
return k&(-k);
}
int bit(int k){
int sum = 0;
while(k){
sum ++;
k -= lowbit(k);
}
return sum;
}
int log2(int k){
for(int i = 0;i<=64;i++){
int p = 1;
if(p<<i==k) return i;
}
return 0;
}
}
using namespace math;
int n,D,g[0b11111],f[0b11111];
map<string,int> mp[0b11111];
string tmp;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
frac[0] = 1;
for(int i = 1;i<=MAXN-1;i++){
frac[i] = frac[i-1]*i;
}
cin >> n >> D;
for(int i = 1;i<=n;i++){
cin >> tmp;
for(int j = 0;j<=(1<<4)-1;j++){
int k = j;
string str = "";
while(k){
str += tmp[math::log2(lowbit(k))];
k -= lowbit(k);
}
mp[j][str]++;
}
}
for(int i = 0;i<=(1<<4)-1;i++){
for(auto j:mp[i]){
g[i] += j.second*(j.second-1)/2;
}
}
int u = 4-D;
D = 4-D;D = (1<<(D-1));
int ans = 0;
for(int S = 0;S<=(1<<4)-1;S++){
for(int T = 0;T<=(1<<4)-1;T++){
if((T&S)==S){
f[S] += qpow(-1,bit(T)-bit(S))*g[T];
}
}
}
// cout << 0b1010 << endl;
for(int i = 0;i<=(1<<4)-1;i++){
if(bit(i)==u){
ans += f[i];
}
}
cout << ans;
return 0;
}