BZOJ3198 SDOI2013 spring HASH+容斥原理

题意:给定6个长度为n的数列,求有多少个数对(i,j)((i,j)≡(j,i))使得i和j位置恰好有K个数相同,其中0≤K≤6

题解:

设fi=至少有K个数相同的位置对的数量,用2^6枚举每一种可能,根据容斥原理,答案就是\[\sum\limits_{i = K}^N {{f_i}C_i^K{{\left( { - 1} \right)}^{i - K}}} \]

至于多乘一个组合数,是因为当前枚举到有x个数相同,一个位置对有i个相同的数,那么累计的时候就会算成$C_x^i$,因此实际上这个位置对对答案的贡献为$\sum\limits_{j = K}^i {C_i^jC_j^K} $

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define L 6
#define U 63
#define B 233
#define P 1234567
#define ll long long

const int MAXK=L+2;
const int MAXP=P+2;
const int MAXN=666666+2;
int a[MAXN][MAXK],Com[MAXK][MAXK],N,K,Cnt[MAXK*MAXK],q[MAXP],f[MAXP],Mark[MAXP],s;
ll Ans;

bool Check(int x,int y,int t){
    for(int i=1;i<=L;i++)
        if((t&(1<<(i-1))) && a[x][i]!=a[y][i]) return 0;
    return 1;
}

void Insert(int t,int p,int x){
    while(Mark[t] && !Check(Mark[t],p,x)) t=(t+1)%P;
    if(!Mark[t]) q[++s]=t,Mark[t]=p;
    f[t]++;
}

ll CalcHash(ll x,int p){
    ll Hash=0;
    for(int i=1;i<=L;i++){
        Hash=Hash*B%P;
        if((1<<(i-1))&x) Hash=(Hash+a[p][i]+1)%P;
    }
    return Hash;
}

int main(){
    cin >> N >> K;
    for(int i=1;i<=N;i++)
        for(int j=1;j<=L;j++)
            scanf("%d",a[i]+j);

    Com[0][0]=1;
    for(int i=1;i<=L;i++){
        Com[i][0]=1;
        for(int j=1;j<=i;j++) Com[i][j]=Com[i-1][j-1]+Com[i-1][j];
    }

    for(int i=1;i<=U;i++) Cnt[i]=Cnt[i>>1]+(i&1);
    for(int i=0;i<=U;i++)
        if(Cnt[i]>=K){
            ll t=0,o=((Cnt[i]-K)&1)?-1:1;
            for(int j=1;j<=N;j++) Insert(CalcHash(i,j),j,i);
            for(int j=1;j<=s;j++) t+=(ll)f[q[j]]*(f[q[j]]-1)/2,f[q[j]]=Mark[q[j]]=0;
            Ans+=o*t*Com[Cnt[i]][K],s=0;
        }
    cout << Ans << endl;

    return 0;
}

时间: 2024-10-13 04:05:32

BZOJ3198 SDOI2013 spring HASH+容斥原理的相关文章

BZOJ 3198 Sdoi2013 spring Hash+容斥原理

题目大意:给定n个元素,每个元素是一个六元组,求有多少对元素满足相同的位置恰好有k个 首先对于恰好有K个这种东西果断考虑容斥原理 我们2^6枚举相同的位置 恰好有k个元素相同的对数=至少有k个位置相同的对数-至少有k+1个位置相同的对数+至少有k+2个位置相同的对数-- 但是我们计数时会发现一些问题 比如下面这组样例显然是0: 2 3 1 2 3 4 5 5 1 2 3 4 6 6 但是这一对元素被加了C(4,3)次,只被减掉了C(4,4)次 因此我们将公式改成这样: 恰好有k个元素相同的对数=

3198: [Sdoi2013]spring【容斥原理+hash】

容斥是ans= 至少k位置相等对数C(k,k)-至少k+1位置相等对数C(k+1,k)+至少k+2位置相等对数*C(k+2,k) -- 然后对数的话2^6枚举状态然后用hash表统计即可 至于为什么要乘上一个组合数,详见 https://www.cnblogs.com/candy99/p/6616809.html 我理解的是,因为是枚举状态统计,所以会重复计算C(k+i,k)次 #include<iostream> #include<cstdio> #include<algo

bzoj3198: [Sdoi2013]spring

Description Input Output 容斥并用hash判断.保存状态,类似bzoj2012 #include<cstdio> int read(){ int x=0,c=getchar(); while(c>57||c<48)c=getchar(); while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x; } int n,k; int w[64],x[6],x0[6]; int K[][7]={

bzoj 3198: [Sdoi2013]spring 题解

[原题] 3198: [Sdoi2013]spring Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 253  Solved: 95 Description Input Output Sample Input 3 3 1 2 3 4 5 6 1 2 3 0 0 0 0 0 0 4 5 6 Sample Output 2 HINT [题解]这道题明明是水题,坑了我两天!!!真是伤心.发现哈希都不熟练了. 首先很容易想到是2^6枚举01状态,使得1

[BZOJ 3198] [Sdoi2013] spring 【容斥 + Hash】

题目链接:BZOJ - 3198 题目分析 题目要求求出有多少对泉有恰好 k 个值相等. 我们用容斥来做. 枚举 2^6 种状态,某一位是 1 表示这一位相同,那么假设 1 的个数为 x . 答案就是 sigma((-1)^(x - k) * AnsNow * C(x, k)) .注意 x 要大于等于 k. 对于一种状态,比如 10110,就是要保证第 1, 3, 4 个值相同. 这些值相同的对数怎么来求呢?使用Hash. 将这些位上的值 Hash 成一个数,然后枚举  [1, i] , 每次求

BZOJ 3198 SDOI2013 spring

为什么SDOI省选一年考两次容斥原理? 我们很容易发现>=k个相等时很好计算的 但是我们要求恰好k个,那么我们容斥即可 至于计算>=k个相等,首先我们枚举相等位置,对每个串对应位置做一遍hash就可以了 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; type

联赛之前的题表(已完成)汇总(可能有遗漏)

联赛之前的搞搞(其实是懒得分类) 博弈论 poj3537 poj1704 hdu5996两个插头 HDU1693 Eat the Trees COGS1283. [HNOI2004] 邮递员kdtree板子1941: [Sdoi2010]Hide and Seek旋转卡壳 pj2187凸包 cogs896 bzoj2829 信用卡凸包莫比乌斯反演基础 bzoj 4173 zhao gui lv bzoj 3529 mobiwus bzoj 4407 mobiwus bzoj 2818 mobiw

bzoj3198【SDOI2013】spring

3198: [Sdoi2013]spring Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 725  Solved: 216 [Submit][Status][Discuss] Description Input Output Sample Input 3 3 1 2 3 4 5 6 1 2 3 0 0 0 0 0 0 4 5 6 Sample Output 2 HINT Dragonite修正数据 Source Hash 容斥原理+哈希 枚举

计数类问题专题

主要是前两天被uoj的毛爷爷的题虐的不轻,心里很不爽啊,必须努力了,, 计数类问题分为:1.组合数学及数论计数 2.dp:状态压缩dp,插头轮廓线dp,树形dp,数位dp,普通dp 3.容斥原理 4.polya原理 5.图论计数 6.生成函数 7.其它(生成树计数等等) 本文主要研究前3个内容 考虑基本计数原理:加法原理,减法原理,乘法原理,除法原理 计数的基本原则:结果不重不漏 加法原理比较自然,中间过程有时减法原理 考虑到无向,有向图的各种量值(生成树之类)计数,状态压缩dp解决 论文:ht