zoukankan      html  css  js  c++  java
  • 题解 洛谷 P3298 【[SDOI2013]泉】

    考虑到年份数很小,只有 (6),所以可以 (2^6) 来枚举子集,确定流量指数对应相同的位置,然后通过哈希和排序来计算相同的方案数。

    但是这样计算出的是大于等于子集元素个数的方案数,所以还需要通过容斥来得到恰好为 (k) 的方案数。设子集元素个数为 (num),其容斥系数为 ((-1)^{num-k}inom{num}{k}),还需乘上组合数的原因是相同个数恰好为 (num) 的方案数对相同个数大于等于 (k) 的方案数的贡献为 (inom{num}{k})

    为了防止被卡,我这里用了双哈希来实现。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 100010
    #define p1 998244353
    #define p2 1000000007
    #define b1 131
    #define b2 137
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    ll n,k,ans;
    ll a[maxn][10],C[10][10];
    bool tag[6];
    struct node
    {
        ll h1,h2;
    }t[maxn];
    bool cmp(const node &a,const node &b)
    {
        if(a.h1==b.h1) return a.h2<b.h2;
        return a.h1<b.h1;
    }
    void init()
    {
        for(int i=0;i<=6;++i) C[i][0]=1;
        for(int i=1;i<=6;++i)
            for(int j=1;j<=i;++j)
                C[i][j]=C[i-1][j]+C[i-1][j-1];
    }
    ll calc(int s)
    {
        for(int i=1;i<=n;++i) t[i].h1=t[i].h2=0;
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=6;++j)
            {   
                t[i].h1=(t[i].h1*b1%p1+a[i][j]*tag[j])%p1;
                t[i].h2=(t[i].h2*b2%p2+a[i][j]*tag[j])%p2;
            }
        }
        sort(t+1,t+n+1,cmp);
        ll cnt=0,sum=0;
        for(int i=2;i<=n;++i)
        {
            if(t[i].h1==t[i-1].h1&&t[i].h2==t[i-1].h2) cnt++,sum+=cnt;
            else cnt=0;
        }
        return sum;
    }
    int main()
    {
        read(n),read(k),init();
        for(int i=1;i<=n;++i)
            for(int j=1;j<=6;++j)
                read(a[i][j]);
        for(int s=0;s<=63;++s)
        {
            int num=0;
            for(int i=1;i<=6;++i)
            {
                if(s&(1<<(i-1))) num++,tag[i]=true;
                else tag[i]=false;
            }
            if(num<k) continue;
            ll val=calc(s)*C[num][k];
            if((num-k)&1) ans-=val;
            else ans+=val;
        }
        printf("%lld",ans);   
        return 0;
    }
    
  • 相关阅读:
    mysql最后一个内容orm
    mysql第五天:
    mysql第二天 数据的增删改查补充及外键
    MYsql 初识
    第二天openc的内容:图片的缩放、旋转、格式转换
    第二个内容第一天 opencv的基本内容:
    第五十七天 bom 的新知识
    第五十六天jQurey的内容新增:
    第五十五天jQery内容的进阶
    windows11 upgrade
  • 原文地址:https://www.cnblogs.com/lhm-/p/13287923.html
Copyright © 2011-2022 走看看