BZOJ 3198 SDOI2013 spring
为什么SDOI省选一年考两次容斥原理?
我们很容易发现>=k个相等时很好计算的
但是我们要求恰好k个,那么我们容斥即可
至于计算>=k个相等,首先我们枚举相等位置,对每个串对应位置做一遍hash就可以了
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> using namespace std; typedef long long LL; const int maxn=100010; const int x=1333331; const int mod=100007; int n,k,lim; int Num[maxn]; int jc[maxn]; LL A[6][maxn]; LL Hash[maxn]; LL ans; void read(int &num){ num=0;char ch=getchar(); while(ch<'!')ch=getchar(); while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar(); } struct HASMMAP{ int h[mod+10],next[200010],cnt; int val[200010]; LL S[200010]; void init(){memset(h,0,sizeof(h));cnt=0;} void push(LL Hash){ int key=Hash%mod; if(key<0)key+=mod; for(int i=h[key];i;i=next[i]){ if(S[i]==Hash){val[i]++;return;} } ++cnt;next[cnt]=h[key];h[key]=cnt; S[cnt]=Hash;val[cnt]=1; } int ask(LL Hash){ int key=Hash%mod; if(key<0)key+=mod; for(int i=h[key];i;i=next[i]){ if(S[i]==Hash)return val[i]; }return 0; } }H; LL Get_ans(int k){ H.init(); LL sum=0; for(int i=1;i<=n;++i){ LL now=0; for(int j=0;j<6;++j){ if(k>>j&1)now=now*x+A[j][i]; } sum+=H.ask(now); H.push(now); }return sum; } LL C(int n,int m){return jc[n]/jc[m]/jc[n-m];} int Get_Num(int k){ int cnt=0; for(int i=0;i<6;++i)if(k>>i&1)cnt++; return cnt; } int main(){ read(n);read(k); for(int i=1;i<=n;++i)for(int j=0;j<6;++j)scanf("%lld",&A[j][i]); jc[0]=1; for(int i=1;i<=6;++i)jc[i]=jc[i-1]*i; lim=(1<<6); for(int i=0;i<lim;++i){ Num[i]=Get_Num(i); if(Num[i]<k)continue; if((Num[i]-k)&1)ans=ans-1LL*C(Num[i],k)*Get_ans(i); else ans=ans+1LL*C(Num[i],k)*Get_ans(i); }printf("%lld\n",ans); return 0; }