[容斥][组合数][暴力]JZOJ 3295 【SDOI2013】泉

Description

济南,中国环渤海地区南翼和黄河中下游地区中心城市,山东省省会,山东省第一大城市,山东省政治、文化、教育中心,华东五大城市之一,区域性金融中心,副省级城市。济南位于山东省中西部,北临黄河,南依泰山。济南分别与西南部的聊城、北部的德州和滨州、东部的淄博、南部的莱芜和泰安交界。济南有着2700 余年的历史,是龙山文化的发祥地。因境内有“七十二名泉”故被称为“泉城”,并素有“四面荷花三面柳,一城山色半城湖”

的美誉。济南历史上涌现了很多文人墨客,著名有李清照、辛弃疾等。济南是国家创新型城市、中国软件名城、全国重要的交通枢纽和物流中心。继济南全运会取得圆满成功后,2013年济南将举办第十届中国艺术节,并成为2015 年“第二十二届国际历史科学大会”的主办城市,为济南建设国际大都市注入了新的活力。

济南市“泉历史研究小组”依据济南特有的泉脉关系将济南的泉水分为六个区域,分别是市中区、历下区、天桥区、槐荫区、历城区、长清区。

作为光荣的济南泉历史研究小组中的一员,铭铭收集了历史上N 个不同年份时不同泉区的泉水流量指数,这个指数是一个小于2^30 的非负整数。第i 个年份时六个泉区的泉水流量指数分别为A(i,1),A(i,2),A(i,3),A(i,4),A(i,5)与A(i,6)。

现在铭铭希望知道有多少对不同的年份:i 和j,满足这两年恰好有K 个泉区的泉水流量指数对应相同。
 

Input

第一行有2 个整数,分别是N 个K。

之后N 行,每行有6 个整数。第i 行的第j 个数字(i,j)表示第i 个年份中第j 个泉区的泉水流量指数。

Output

只一行,一个整数。表示有多少对不同的年份,满足恰有K 个泉区的泉水流量指数对应相同。
 

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
 

Data Constraint

有8%的数据,N<=1000,A<=20

有8%的数据,N<=1000,A<=2^30

有24%的数据,N<=100000,A<=20

有28%的数据,N<=10000,A<=2^30

有32%的数据,N<=100000,A<=2^30

对于100%的数据,0<=K<=6,且所有数据中K 是等概率出现的,即对于任意的0<=x<=6,都有大约1/7 的数据中K=x。

分析

题意为在n个六元组中求出有多少对满足刚好k个对应位置的量相等

k很小,我们可以枚举所有2^6种状况

我们发现刚好有k种的情况比较难做,不如考虑至少k种的

设至少k种的情况为f[k]

那么ans=f[k]-f[k+1]*C(k+1,k)+f[k+2]*C(k+2,k)-f[k+3]*C(k+3,k)+……

k+x<=6

为什么要乘上C(k+x,k)呢?我们可以发现每个刚好为k+x的情况都可以对答案产生C(k+x,k)的贡献

 

#include <iostream>
#include <cstdio>
#include <memory.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=1e5+10;
const int P=17453343;
const int Typi=133345;
struct List {
    ull v;
    int nx,cnt;
}l[N];
int cnt,list[P];
int n,k;
int a[N][7];
ll ans,C[7][7];

void Insert(ull x) {
    int u=x%P;
    for (int i=list[u];i;i=l[i].nx)
        if (l[i].v==x) {
            l[i].cnt++;
            return;
        }
    l[++cnt]=(List){x,list[u],1};list[u]=cnt;
}

void Calc(int m) {
    int rnt=0;
    for (int i=0;i<6;i++) if (m&(1<<i)) rnt++;
    if (rnt<k) return;
    memset(list,0,sizeof list);cnt=0;
    for (int i=1;i<=n;i++) {
        ull hash=0;
        for (int j=0;j<6;j++)
            if (m&(1<<j)) hash=hash*Typi+a[i][j];
        Insert(hash);
    }
    ll count=0;
    for (int i=1;i<=cnt;i++) count+=1ll*l[i].cnt*(l[i].cnt-1)/2;
    count*=C[rnt][k];
    ans+=((rnt-k)%2?-1:1)*count;
}

int main() {
    C[0][0]=1;
    for (int i=1;i<=6;i++) {
        C[i][0]=1;
        for (int j=1;j<=i;j++)
            C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++)
        for (int j=0;j<6;j++) scanf("%d",&a[i][j]);
    for (int i=0;i<(1<<6);i++)
        Calc(i);
    printf("%lld",ans);
}
View Code

 

posted @ 2019-06-28 20:47  Vagari  阅读(190)  评论(0编辑  收藏  举报