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 }
View Code

 

posted @ 2017-03-23 12:44  lawyer'  阅读(177)  评论(0编辑  收藏  举报