Table
题意:
要求对一个n*m的网格染色,使得任意一个n*n大小的矩形内恰好有K个格子被染色。
解法:
减弱版的color,可以注意到只要确定了前n列,则后面的列是一个循环。
这样$f(i,j)$表示前i列,染了j个格子对应的给n*m的方格按列循环染色的方案数。
$f(i,j) = \sum_{k \le min(j,n)} {f(i-1,j-k) \cdot {C_n^k}^{[m/i]}}$
复杂度$O(n^2*K)$。
当然,设$g(i,k) = {C_n^k}^{[m/i]}$。
那么可以注意到 $f(i) = f(i-1) \otimes g(i)$
fft,复杂度$O(nKlogK)$
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 #define LL long long 6 #define P 1000000007LL 7 #define N 110 8 9 using namespace std; 10 11 int n,K; 12 LL f[N][N*N],g[N*N]; 13 14 LL qpow(LL x,LL n) 15 { 16 LL ans=1; 17 for(;n;n>>=1,x=x*x%P) 18 if(n&1) ans=ans*x%P; 19 return ans; 20 } 21 22 int main() 23 { 24 LL m; 25 while(~scanf("%d%I64d%d",&n,&m,&K)) 26 { 27 f[0][0]=1; 28 for(int i=1;i<=n;i++) 29 { 30 LL tmp=1; 31 for(int j=0;j<=n;j++) 32 { 33 g[j] = qpow(tmp, (m+n-i)/n); 34 tmp = tmp * qpow(j+1LL,P-2)%P; 35 tmp = tmp * (n-j+0LL)%P; 36 } 37 for(int j=0;j<=K;j++) 38 { 39 f[i][j]=0; 40 for(int k=0;k<=min(j,n);k++) 41 { 42 f[i][j] += f[i-1][j-k] * g[k]%P; 43 if(f[i][j] >= P) f[i][j] -= P; 44 } 45 } 46 } 47 cout << f[n][K] << endl; 48 } 49 }