URAL 1932 The Secret of Identifier(容斥)
Description
Davy Jones: You've been captain of the Black Pearl for 13 years. That was our agreement. Jack: Technically I was only captain for two years, then I was mutinied upon. Davy Jones: Then you were a poor captain, but a captain nonetheless. Have you not introduced yourself as Captain Jack Sparrow?
According to the Pirate Code, each of the pirates of the Caribbean at the beginning of their professional career (hereditary pirates –– at birth) is assigned by a unique identifier. Pirate's identifier is a string of four hexadecimal digits. However, it is not a usual row of numbers, it is said that personal qualities and life path of its owner are encoded in it by a mysterious way. But no one still could guess this mystical connection.
Once Captain Jack Sparrow, while sitting in captain’s cabin, decided to try to find the way to derive some data about a pirate using the identifier. Memories about how he lost the Black Pearl last time gave him the idea that more similar identifiers of two pirates are, bigger chances for these pirates to unite against the Captain, and, as a result, to make a mutiny. The Captain Jack Sparrow, of course, doesn’t want to have the mutiny on his ship, but he chose the new team this time and it is going to be a long voyage. Now Jack needs to estimate the opportunities of raising the mutiny on his ship, based on the conclusions. For this aim he first wants to know for each pair of pirates a number of positions in their identifiers in which they are different.
Input
The first line contains an integer n –– the number of pirates aboard the Black Pearl (2 ≤ n ≤ 65536). Each of the following n lines contains four-digit identifier of the respective pirate. Only decimal digits and lowercase Latin letters from “a” to “f” inclusive are used in writing identifiers. Identifiers of all pirates are different.
Output
Output four space separated integers –– the amount of pairs of pirates, which have different identifiers exactly in one, two, three and four positions respectively.
题目大意:给n个字符串,每个字符串有4个字符(其实是4位16进制数),输出这些字符串中有1位不同的字符串个数、有2位不同的字符串个数、有3位不同的字符串个数、有4位不同的字符串个数.
思路:用一个数组sum[i][j]存下在状态 i 下 j 的出现次数,如sum[3][244]就代表XXF4的出现次数:其中3是二进制的0011,代表是计算最后两位的出现次数,前面两位为任意字符;F4(10进制为244)则为后两位为F4的字符串的出现次数;XX为任意字符。
那么,扫一遍,统计一下,就能知道:一个字符相同的对数、两个字符相同的对数、三个字符相同的对数。注意,这样算的时候,如aaaa和aaab,这个一个字符相同的对数是算了3遍的,所以要减回去。
至于怎么减回去大概可以用容斥原理,我写的那些其实是我自己YY的,我不会容斥o(╯□╰)o
代码(62MS):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 using namespace std; 6 typedef long long LL; 7 8 LL sum[16][1 << 16]; 9 char s[6]; 10 int n, maxl; 11 12 inline int trans(char c) { 13 if(isdigit(c)) return c - '0'; 14 return c - 'a' + 10; 15 } 16 17 void init() { 18 for(int p = 0; p < n; ++p) { 19 scanf("%s", &s[1]); 20 for(int i = 1; i <= 15; ++i) { 21 int t = 0; 22 if(i&8) t += trans(s[1]) * (1<<12); 23 if(i&4) t += trans(s[2]) * (1<<8); 24 if(i&2) t += trans(s[3]) * (1<<4); 25 if(i&1) t += trans(s[4]); 26 ++sum[i][t]; 27 maxl = max(maxl, t); 28 } 29 } 30 } 31 32 LL ans[5], tmp[5]; 33 34 inline int bit_count(int x) { 35 int ret = 0; 36 while(x > 0) ret += (x & 1), x >>= 1; 37 return ret; 38 } 39 40 void solve() { 41 for(int i = 1; i <= 15; ++i) { 42 int x = bit_count(i); 43 for(int j = 0; j <= maxl; ++j) tmp[x] += sum[i][j] * (sum[i][j] - 1) / 2; 44 } 45 ans[1] = tmp[3];//1位不同=3位相同 46 ans[2] = tmp[2] - 3 * tmp[3]; 47 ans[3] = tmp[1] - 2 * tmp[2] + 3 * tmp[3]; 48 ans[4] = LL(n - 1) * n / 2 - ans[1] - ans[2] - ans[3]; 49 cout<<ans[1]<<' '<<ans[2]<<' '<<ans[3]<<' '<<ans[4]<<endl; 50 } 51 52 int main() { 53 scanf("%d", &n); 54 init(); 55 solve(); 56 }