zoukankan      html  css  js  c++  java
  • BZOJ5487: [Usaco2018 Dec]Cowpatibility

    Description

    研究证明,有一个因素在两头奶牛能否作为朋友和谐共处这方面比其他任何因素都来得重要——她们是不是喜欢同

    一种口味的冰激凌!Farmer John的N头奶牛(2≤N≤50,000)各自列举了她们最喜欢的五种冰激凌口味的清单。为

    使这个清单更加精炼,每种可能的口味用一个不超过106的正整数ID表示。如果两头奶牛的清单上有至少一种共同

    的冰激凌口味,那么她们可以和谐共处。请求出不能和谐共处的奶牛的对数。

    Input

    输入的第一行包含N

    以下N行每行包含5个整数(各不相同),表示一头奶牛最喜欢的冰激凌口味。

    Output

    输出不能和谐共处的奶牛的对数。

    Sample Input

    4
    1 2 3 4 5
    1 2 3 10 8
    10 9 8 7 6
    50 60 70 80 90

    Sample Output

    4
    在这里,奶牛4不能和奶牛1、2、3中的任一头和谐共处,奶牛1和奶牛3也不能和谐共处。

    HINT

    Source

    Gold

    Solution

    正解是容斥(然而我并不会,只会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('
    ')
    
    #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('
    ')
     
    #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);
    }
    
  • 相关阅读:
    Oracle自增ID实现
    mysql5修改用户密码及远程访问
    关于线程中修改UI的控件属性
    Javascript 保持浮动位置
    Linq To Entity 查询条件扩展
    反转字符顺序
    VB6.0 二分法解方程
    支持库:FileHelper
    C# 计算加减乘除
    Linq.GroupBy使用示例
  • 原文地址:https://www.cnblogs.com/henry-1202/p/10633073.html
Copyright © 2011-2022 走看看