研究证实,有一个因素在两头奶牛可否做为朋友和谐共处这方面比其余任何因素都来得重要——她们是否是喜欢同php
一种口味的冰激凌!Farmer John的N头奶牛(2≤N≤50,000)各自列举了她们最喜欢的五种冰激凌口味的清单。为c++
使这个清单更加精炼,每种可能的口味用一个不超过106的正整数ID表示。若是两头奶牛的清单上有至少一种共同学习
的冰激凌口味,那么她们能够和谐共处。请求出不能和谐共处的奶牛的对数。优化
输入的第一行包含Nspa
如下N行每行包含5个整数(各不相同),表示一头奶牛最喜欢的冰激凌口味。code
输出不能和谐共处的奶牛的对数。ip
4
1 2 3 4 5
1 2 3 10 8
10 9 8 7 6
50 60 70 80 90get
4
在这里,奶牛4不能和奶牛一、二、3中的任一头和谐共处,奶牛1和奶牛3也不能和谐共处。input
Goldstring
正解是容斥(然而我并不会,只会bitset优化暴力,去找题解学习了一下容斥作法)。
不过bzoj好像调了时限,而后我如今网上找到的全部容斥题解都TLE了(由于网上的题解都用了string,换成hash才能过)。
容斥作法:
显然转化为\(n(n-1)/2-\)和谐对数。
而后和谐对数就5种状况:1个同样的,2个同样的,3个同样的,4个同样的,5个同样的。
用经典的容斥式子:
\[ ans=\sum_{i=1}^5f(i)*(-1)^i \]
\(f(i)\)为同样的对数的个数。
那么\(2^5\)枚举全部取法,容斥一遍便可。
复杂度是相对与用string的小常数\(O(2^5nlogn)\)
用bitset优化一下暴力也跑的飞快,就慢了几百ms。复杂度是小常数的\(O(\frac{n^2logn}{w})\)(要开map否则存不下,或者能够分块求答案就不用开map)。
容斥作法:
#include <bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define il inline #define ull unsigned long long namespace io { #define in(a) a = read() #define out(a) write(a) #define outn(a) out(a), putchar('\n') #define I_int ll inline I_int read() { I_int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } char F[200]; inline void write(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); } #undef I_int } using namespace io; using namespace std; #define N 50010 #define base 23333333 int n = read(); int a[10]; map<ull,ll>mp; int main() { ll ans = 1ll*n*(n-1ll)/2ll; for(int i = 1; i <= n; ++i) { for(int j = 0; j < 5; ++j) in(a[j]); sort(a,a+5); ll sum = 0; for(int k = 1; k < (1 << 5); ++k) { int tot = 0; ull s = 0; for(int j = 0; j < 5; ++j) if(k&(1<<j)) s = s * base + a[j], ++tot; if(tot&1) sum += mp[s]++; else sum -= mp[s]++; } ans -= sum; } outn(ans); }
bitset作法
#include <bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f #define il inline #define ull unsigned long long namespace io { #define in(a) a = read() #define out(a) write(a) #define outn(a) out(a), putchar('\n') #define I_int ll inline I_int read() { I_int x = 0, f = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); } while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } return x * f; } char F[200]; inline void write(I_int x) { if (x == 0) return (void) (putchar('0')); I_int tmp = x > 0 ? x : -x; if (x < 0) putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0) putchar(F[--cnt]); } #undef I_int } using namespace io; using namespace std; #define N 50010 int n = read(); int a[N][5]; map<int, bitset<50005> > t; int main() { for(int i = 1; i <= n; ++i) { for(int j = 0; j < 5; ++j) { in(a[i][j]); t[a[i][j]][i] = 1; } } ll ans = 0; for(int i = 1; i <= n; ++i) { bitset<50005>tmp; tmp.reset(); for(int j = 0; j < 5; ++j) { tmp |= t[a[i][j]]; } ans+=n - tmp.count(); } outn(ans/2ll); }