• [BZOJ3198][SDOI2013]Spring(容斥+Hash)


    给定n个六元数,问有多少对数有m元对应相等。

    考虑“有多少对数至少m元对应相等”的求法,显然枚举相等的位置,在这些位置上Hash统计即可。

    容斥定理:至少有k个的-C(k+1,k)* 至少有k+1个的+C(k+2,k) *至少有k+2个的…=恰好有k个的。

    按上式容斥,问题得解。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=100010,mod1=131,mod2=1e6+33;
     9 int n,m,cnt,a[N][7],C[7][7],h[mod2+10],to[N],nxt[N];
    10 ll ans,sm[N];
    11 
    12 bool chk(int x,int y,int k){
    13     rep(i,1,6) if (k&(1<<(i-1)) && a[x][i]!=a[y][i]) return 0;
    14     return 1;
    15 }
    16 
    17 ll calc(int S){
    18     ll res=0; cnt=0;
    19     memset(h,0,sizeof(h));
    20     rep(i,1,n){
    21         ll x=0; int p=0;
    22         rep(j,1,6) if (S&(1<<(j-1))) x=(x*mod1+a[i][j])%mod2;
    23         for (p=h[x]; p; p=nxt[p])
    24             if (chk(to[p],i,S)) { res+=sm[p]; sm[p]++; break; }
    25         if (!p) to[++cnt]=i,sm[cnt]=1,nxt[cnt]=h[x],h[x]=cnt;
    26     }
    27     return res;
    28 }
    29 
    30 int main(){
    31     freopen("bzoj3198.in","r",stdin);
    32     freopen("bzoj3198.out","w",stdout);
    33     scanf("%d%d",&n,&m);
    34     rep(i,1,n) rep(j,1,6) scanf("%d",&a[i][j]);
    35     C[0][0]=1; rep(i,1,6){ C[i][0]=1; rep(j,1,i) C[i][j]=C[i-1][j-1]+C[i-1][j]; }
    36     rep(S,0,63){
    37         int cnt=0;
    38         rep(i,0,5) if (S&(1<<i)) cnt++;
    39         if (cnt<m) continue;
    40         ll t=calc(S)*C[cnt][m];
    41         ans+=((cnt-m)&1) ? -t : t;
    42     }
    43     printf("%lld
    ",ans);
    44     return 0;
    45 }
  • 相关阅读:
    Android相关sdk使用
    Uniscribe文字自动换行
    Chrome RenderText分析(2)
    c++智能指针
    codepage IMLangCodePages
    GUI 快捷键的实现思路
    买车险
    九年---祝爱永存!
    算法
    Windows内核安全与驱动开发
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9806183.html
Copyright © 2020-2023  润新知