Sol:
对月份进行枚举,也就是说看在这些月份中,N行中,有哪些行是两两相等的
至于判相等,则使用Hash表进行存储与查找.
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define ll long long #define N 100005 #define mod 2150527 using namespace std; int a[N][10],bin[10],hd[mod+10],vis[mod+10],c[10][10],sum[N],nxt[N],n,m; ll val[N]; void pre() { for(int i=0;i<=6;i++) c[i][0]=c[i][i]=1; for(int i=1;i<=6;i++) for(int j=1;j<i;j++) c[i][j]=c[i-1][j-1]+c[i-1][j]; } ll calc(int st) { ll ans=0;int tot=0; for(int i=1;i<=n;i++)//枚举行 { ll tmp=0;int j,k; for(j=1;j<=6;j++)//对于每行的六个数字 if(st&bin[j-1])//看哪些月份在我们枚举的范围内 tmp=tmp*1000003+a[i][j]; //将其hash出来 j=tmp%mod; j<0?j+=mod:1; if(vis[j]!=st) { vis[j]=st; hd[j]=0; } for(k=hd[j];k;k=nxt[k]) { if(val[k]==tmp) { ans+=sum[k]; sum[k]++; break; } } if(!k) { val[++tot]=tmp; sum[tot]=1; nxt[tot]=hd[j]; hd[j]=tot; } } return ans; //统计对于N行,在我们枚举的月份内,有多少对是相互相等的 } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=6;j++) scanf("%d",&a[i][j]); bin[0]=1; pre(); for(int i=1;i<=8;i++) bin[i]=bin[i-1]<<1; ll ans=0; for(int i=0;i<64;i++) //枚举月份,统计对于N行来说,它们在这i个月有多少个是互相相等的 //由于对其它月份没有统计,所以是至少这i个月是互相相等的 { int cnt=0; for(int j=0;j<6;j++) //看有效月份有几个 if(i&bin[j]) cnt++; if(cnt<m) continue; ll t=calc(i)*c[cnt][m]; if((cnt-m)%2) ans-=t; else ans+=t; } cout<<ans; return 0; }