题目
思路
首先考虑 d p \tt dp dp ,不行再换一个方法。
用 f ( x , y ) f(x,y) f(x,y) 表示,填了前 x x x 行,有 y y y 列还没有满足 min = 1 \min=1 min=1 。转移则可枚举,这 y y y 列中有 i i i 列填了 1 1 1 ,所以有
f ( x + 1 , y − i ) += ( y i ) ( k − 1 ) y − i k n − y f ( x , y ) f(x+1,y-i)\;\text{+=}\;{y\choose i}(k-1)^{y-i}k^{n-y}f(x,y) f(x+1,y−i)+=(iy)(k−1)y−ikn−yf(x,y)
特殊考虑这一行没有 1 1 1 的情况。所以 f ( x + 1 , y ) − = f ( x , y ) ( k − 1 ) n f(x+1,y)\;-\text{=}\;f(x,y)(k-1)^{n} f(x+1,y)−=f(x,y)(k−1)n
即 f ( x , y ) = ∑ i = 0 n − y ( y + i i ) ( k − 1 ) y k n − y − i f ( x − 1 , y + i ) − f ( x − 1 , y ) ( k − 1 ) n f(x,y)=\sum_{i=0}^{n-y}{y+i\choose i}(k-1)^yk^{n-y-i}f(x-1,y+i)-f(x-1,y)(k-1)^{n} f(x,y)=i=0∑n−y(iy+i)(k−1)ykn−y−if(x−1,y+i)−f(x−1,y)(k−1)n
我没有找到很好的方式去优化它。大概只能做到 O ( n 3 ) \mathcal O(n^3) O(n3) 吧。
换个思路,用容斥计算有 a a a 行 b b b 列没有 1 1 1 的情况。所以答案为
∑ a = 0 n ∑ b = 0 n ( − 1 ) a + b ( n a ) ( n b ) ( k − 1 ) ( a + b ) n − a b k ( n − a − b ) n + a b = ∑ a = 0 n ( − 1 ) a ( n a ) ( k − 1 ) a n k ( n − a ) n ∑ b = 0 n ( − 1 ) b ( n b ) ( k − 1 ) b n − a b k a b − b n \begin{aligned} &\sum_{a=0}^{n}\sum_{b=0}^{n}(-1)^{a+b}{n\choose a}{n\choose b}(k-1)^{(a+b)n-ab}k^{(n-a-b)n+ab}\\ =&\sum_{a=0}^{n}(-1)^a{n\choose a}(k-1)^{an}k^{(n-a)n}\sum_{b=0}^{n}(-1)^{b}{n\choose b}(k-1)^{bn-ab}k^{ab-bn} \end{aligned} =a=0∑nb=0∑n(−1)a+b(an)(bn)(k−1)(a+b)n−abk(n−a−b)n+aba=0∑n(−1)a(an)(k−1)ank(n−a)nb=0∑n(−1)b(bn)(k−1)bn−abkab−bn
令 f ( x ) = ∑ i = 0 n ( − 1 ) i ( n i ) x i f(x)=\sum_{i=0}^{n}(-1)^i{n\choose i}x^i f(x)=i=0∑n(−1)i(in)xi
容易发现这就是二项式展开。当 2 ∣ n 2|n 2∣n 时 f ( x ) = ( x − 1 ) n f(x)=(x-1)^{n} f(x)=(x−1)n ;否则 f ( x ) = − ( x − 1 ) n f(x)=-(x-1)^{n} f(x)=−(x−1)n 。
但是答案会被巧妙的化简: ∑ a = 0 n ( − 1 ) a ( n a ) ( k − 1 ) a n k ( n − a ) n × f [ ( k − 1 k ) n − a ] \sum_{a=0}^{n}(-1)^{a}{n\choose a}(k-1)^{an}k^{(n-a)n}\times {\Large f}\left[\left(\frac{k-1}{k}\right)^{n-a}\right] a=0∑n(−1)a(an)(k−1)ank(n−a)n×f[(kk−1)n−a]
复杂度 O ( n log n ) \mathcal O(n\log n) O(nlogn) ,足以优秀地通过本题。
代码
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long int_;
inline int readint(){
int a = 0; char c = getchar(), f = 1;
for(; c<'0'||c>'9'; c=getchar())
if(c == '-') f = -f;
for(; '0'<=c&&c<='9'; c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
const int Mod = 1e9+7;
inline int qkpow(int_ b,int q){
int a = 1;
for(; q; q>>=1,b=b*b%Mod)
if(q&1) a = a*b%Mod;
return a;
}
const int MaxN = 252;
int jc[MaxN], inv[MaxN], n;
void prepare(){
jc[1] = inv[1] = 1;
for(int i=2; i<=n; ++i){
jc[i] = 1ll*jc[i-1]*i%Mod;
inv[i] = (0ll+Mod-Mod/i)*inv[Mod%i]%Mod;
}
for(int i=2; i<=n; ++i)
inv[i] = 1ll*inv[i-1]*inv[i]%Mod;
jc[0] = inv[0] = 1;
}
int getC(int x,int y){
if(y < 0 || x < y) return 0;
return 1ll*jc[x]*inv[y]%Mod*inv[x-y]%Mod;
}
int f(int x){
x = qkpow(x-1,n);
return (n&1) ? Mod-x : x;
}
int main(){
n = readint(); int k = readint();
prepare(); // prepare for C
int invk = qkpow(k,Mod-2);
int k_1n = qkpow(k-1,n);
int one = 1; // k_1n ^ a
int invkn = qkpow(invk,n);
int two = qkpow(k,1ll*n*n%(Mod-1));
int ans = 0;
for(int i=0; i<=n; ++i){
int c = (k-1ll)*invk%Mod;
c = f(qkpow(c,n-i));
c = 1ll*c*one%Mod*two%Mod;
c = 1ll*c*getC(n,i)%Mod;
if(i&1) ans = (ans+Mod-c)%Mod;
else ans = (ans+c)%Mod;
one = 1ll*one*k_1n%Mod;
two = 1ll*two*invkn%Mod;
}
printf("%d\n",ans);
return 0;
}