您的位置:首页 > 编程语言 > Java开发

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

2018-10-17 18:27 225 查看

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

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

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

按上式容斥,问题得解。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std;

const int N=100010,mod1=131,mod2=1e6+33;
int n,m,cnt,a
[7],C[7][7],h[mod2+10],to
,nxt
;
ll ans,sm
;

bool chk(int x,int y,int k){
rep(i,1,6) if (k&(1<<(i-1)) && a[x][i]!=a[y][i]) return 0;
return 1;
}

ll calc(int S){
ll res=0; cnt=0;
memset(h,0,sizeof(h));
rep(i,1,n){
ll x=0; int p=0;
rep(j,1,6) if (S&(1<<(j-1))) x=(x*mod1+a[i][j])%mod2;
for (p=h[x]; p; p=nxt

) if (chk(to[p],i,S)) { res+=sm[p]; sm[p]++; break; } if (!p) to[++cnt]=i,sm[cnt]=1,nxt[cnt]=h[x],h[x]=cnt; } return res; } int main(){ freopen("bzoj3198.in","r",stdin); freopen("bzoj3198.out","w",stdout); scanf("%d%d",&n,&m); rep(i,1,n) rep(j,1,6) scanf("%d",&a[i][j]); 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]; } rep(S,0,63){ int cnt=0; rep(i,0,5) if (S&(1<<i)) cnt++; if (cnt<m) continue; ll t=calc(S)*C[cnt][m]; ans+=((cnt-m)&1) ? -t : t; } printf("%lld\n",ans); return 0; }

[p] 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: