研究證實,有一個因素在兩頭奶牛可否做爲朋友和諧共處這方面比其餘任何因素都來得重要——她們是否是喜歡同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); }