[CEOI2010 day2] pin

[CEOI2010 day2] pin

题目信息

题目链接

Luogu P6521

题目描述

给定 \(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\) 或者数字字符。

说明

题目译自 CEOI 2010 day 2 T2 pin

思路分析

恰好有 \(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;
}
posted @ 2024-05-29 14:42  辜铜星  阅读(11)  评论(0编辑  收藏  举报