【USACO18DEC】【 bitset | 容斥 】Cowpatibility

题目链接

【小结】:

这个题目,我一刹那间觉得是容斥,但是无法表示任意两个冰淇淋之间的交集,后来看了洛谷题解中各显神通,这个神通真的太强了,让我学习了一个新的容器bitset,还有一个是我以前一直有想法但是从未实现过的字符串哈希思路。我以前就在某些题上有思路的,但是这个题目让我再次容光焕发,原来自己以前的想法真的有实现过,这个感觉非常好。

【题解】:

有n头牛,然后每头牛都喜欢5种不同口味的冰淇淋,但是两头牛之间有矛盾,就是没有相同喜欢的冰淇淋口味。请问有多少头牛之间是有矛盾的。刹那间觉得是容斥,源于我们之前山东省省赛时一道题,有相通的地方,但是当时的那个题目我们没有做出来,赛后也是看了别人的题解坑坑洼洼地做出来的。其实我们是做不出来的。所以一直是一个遗憾。看到这个题目就想到2^5次方情况,用二进制枚举的一个容斥题目,但是至于怎么进行把这个选中多种冰淇淋呢???这个就需要用字符串哈希了,用#来分割,然后把每一个数字转化为字符串,把他们拼接起来,然后进行用mp标记。

具体看代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+10;
string a[6];
map<string ,int>Mp;
int main()
{
    ll n,Len=1<<5,ans;
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin>>n;
    ans=(n-1)*n/2;
    for(int i=1;i<=n;i++){
        for(int j=0;j<5;j++){
            cin>>a[j];
        }
        sort(a,a+5);
        int t=0;
        for(int k=1;k<Len;k++){
            int cnt=0;
            string s="";
            for(int j=0;j<5;j++){
                if(k&(1<<(j))){
                    cnt++;
                    s+="#"+a[j];
                }
            }
            if(cnt&1) t+=Mp[s]++;
            else      t-=Mp[s]++;
        }
        ans-=t;
    }
    cout<<ans<<endl;
    return 0;
}

然后在题解中,各显神通的时候来了,bitset。一直都不知道是什么来的,这次我总算是体会了一波,它的做法就是把每一头牛设置为bitset上面的对应的一位,Mp<int, bitset<N> >,就是Mp[ 口味 ]为一个bitset。然后这个bitset内就是喜欢这个口味的牛,n-count表明就是不喜欢这种口味的牛的个数,然后历遍n头牛即可。

附上:胡小兔的bitset用法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+10;
map<int,bitset<N> >mp;
int a[N][5];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=0;j<5;j++){
            scanf("%d",&a[i][j]);
            mp[a[i][j]].set(i);
        }
    }
    ll ans=0;
    bitset<N>t;
    for(int i=1;i<=n;i++){
        t.reset();
        for(int j=0;j<5;j++)
            t|=mp[a[i][j]];
        
        ans+=n-t.count();
    }
    printf("%lld\n",ans/2);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Z_sea/article/details/87370907