感觉是个套路题,不是特别难(然而卡常
直接做不可做,改成算每个数的贡献
暴力的想法是容斥,即记录每个数在每行里的出现情况,从总方案中扣掉每一行都没选到这个数的方案,复杂度$O(n^3)$
我们发现很多时候一行里根本没有这个数,也就是说很多情况下都白枚举了,我们可以尝试直接对每个数求方案。具体来说我们把每个数出现的行丢进一个vector里,然后vector里一段相同的就是它在这行出现的次数,没出现的行可以直接算出来,这样复杂度就变成$O(n^2log^2 n)$了,然后你就可以开始卡常了
用了fread+register+指针+unsigned int+const 才在 EOJ 上卡过去,我佛了
1 #pragma GCC optimize(2) 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 #include<algorithm> 6 #define uint unsigned int 7 #define vint vector<uint> 8 using namespace std; 9 const int N=2005; 10 const uint mod=1e9+7; 11 vint vec[N*N]; 12 uint n,m,rd,all,tot,ans; 13 uint a[N][N],pw[N],uni[N*N]; 14 15 char BF[1<<23],*P1=BF,*P2=BF; 16 char Gc(){return (P1==P2&&(P2=(P1=BF)+fread(BF,1,1<<21,stdin),P1==P2)?EOF:*P1++);} 17 void Fread(uint &x) 18 { 19 x=0; char ch=Gc(); 20 while(!isdigit(ch)) ch=Gc(); 21 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=Gc(); 22 } 23 24 void Add(uint &x,uint y) 25 { 26 x+=y; 27 if(x>=mod) x-=mod; 28 } 29 int main() 30 { 31 register uint i,j,k; 32 Fread(m),Fread(n); 33 for(i=1;i<=n;i++) 34 for(j=1;j<=m;j++) 35 Fread(rd),uni[++tot]=*(*(a+i)+j)=rd; 36 sort(uni+1,uni+1+tot); 37 const uint lth=unique(uni+1,uni+1+tot)-uni-1; 38 for(i=1;i<=n;i++) 39 for(j=1;j<=m;j++) 40 { 41 const uint t=lower_bound(uni+1,uni+1+lth,*(*(a+i)+j))-uni; 42 vec[*(*(a+i)+j)=t].push_back(i); 43 } 44 for(i=pw[0]=1;i<=n;i++) pw[i]=1ll*pw[i-1]*m%mod; 45 for(i=1;i<=lth;i++) 46 { 47 uint tmp=pw[n],tep=1,res=n; 48 const uint siz=vec[i].size(); 49 vint ve=vec[i]; 50 for(j=0;j<siz;j=k+1) 51 { 52 k=j; 53 while(k+1<siz&&ve[j]==ve[k+1]) k++; 54 tep=1ll*tep*(m-(k-j+1))%mod,res--; 55 } 56 tep=1ll*tep*pw[res]%mod; 57 Add(tmp,mod-tep),Add(ans,1ll*tmp*uni[i]%mod); 58 } 59 printf("%d",ans); 60 return 0; 61 }