题目链接:http://codeforces.com/contest/233/problem/D
题意:问在n*m的矩阵中满足在每一个n*n的矩阵里画k个点,一共有几种画法。
题解:其实这题挺简单的但是有一个优化要注意一下,接下来将一下这题的解法。
拿一个连续长度为n的块。1,2将其分成3部分第一部分为第一列a,第二部分为中间重合的部分,第三部分为最后一列c设Si表示,第i列一共有几个点。
显然Sa=Sc于是乎便有思路了吧,所有可能性就是1~n的C(n,k)^cnt(cnt是m/n or m/n + 1)然后用dp[i][j]来存第i个有j个点的一共有几种,然后
转移一下就行具体怎么转移法看代码。
#include <iostream> #include <cstring> #include <cstdio> #define mod 1000000007 using namespace std; typedef long long ll; ll c[200][200] , dp[110][10010]; //这里要用到快快速幂毕竟最多有1e18次。 ll modexp(ll a , ll b) { ll ret = 1; ll tmp = a; while(b) { if(b & 0x1) ret = ret * tmp % mod; tmp = tmp * tmp % mod; b >>= 1; } return ret; } int main() { ll n , m , k; scanf("%lld%lld%lld" , &n , &m , &k); for(int i = 1 ; i <= 100 ; i++) c[i][1] = i , c[i][i] = 1 , c[i][0] = 1; for(int i = 2 ; i <= 100 ; i++) { for(int j = 2 ; j < i ; j++) c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod; }//预处理组合数 memset(dp , 0 , sizeof(dp)); ll cnt = m / n; ll gb; if(m % n) { gb = m - n * cnt; cnt++; } else gb = n; //gb在这里起指示作用,当整除的时候一共有cnt-1对,不能整除的话有gb个是cnt对的剩下cnt-1对。 for(int i = 0 ; i <= n ; i++) dp[i][0] = 1; for(int i = 1 ; i <= n ; i++) { //注意这个优化求次方一定要在外层不然会超时。 for(int j = 0 ; j <= n && j <= k ; j++) { ll gg = c[n][j]; ll gl; if((ll)i <= gb) gl = modexp(gg , cnt); else gl = modexp(gg , cnt - 1); for(int l = j ; l <= k ; l++) { if(l == 0) continue;//细节稍微注意一下 dp[i][l] += dp[i - 1][l - j] * gl; dp[i][l] %= mod; } } } printf("%lld " , (dp[n][k] + mod) % mod); return 0; }