题目链接: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;
}