您的位置:首页 > 其它

Table CodeForces - 232B(144 div1 B) (dp+快速幂)

2017-08-15 08:13 567 查看
链接:http://codeforces.com/problemset/problem/232/B

题意:给出一个n*m的大矩阵(m>=n),往矩阵里放点,求满足对于每一个n*n的小矩阵都有k个点的放法的数量。

解题思路:



对于一个n*n的矩阵S1 A为其左边一列中的点的个数, B为S2右边一列中的点的个数, 于是有A+T=B+T ,故当第一个n⋅n 矩阵中第i列的点的个数确定时,第n+i, n+2*i….点的个数都会被确定, 于是问题转化为求第一个n*n矩阵中每一列的点的个数 ,记dp[i][j]为当到第i列时共确定了j个点, 则不难推出dp[i][j]=∑min(n,j)x=0dp[i−1][j−x]⋅Cxn , 用语言描述就是第i列确定j个点这种情况是由第i-1列确定j-x个点乘在n个点中挑选x个点的情况数,当然这里的Cxn要考虑到对后面第n+i, n+2*i….点的影响。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define LL long long
using namespace std;
const int MOD = 1e9 + 7;
const int Max = 120;
LL C[Max][Max];
LL Z[Max][Max];
LL dp[Max][15000];

void get_combinations() {//递推求出组合数
for (int a = 1; a <= 100; a++) {
C[a][0] = C[a][a] = 1;
for (int b = 1; b < a; b++) {
C[a][b] = (C[a - 1][b - 1] + C[a - 1][b]) % MOD;//对于某一个点如果确定取则为 C[a - 1][b - 1], 确定不取为C[a - 1][b]
}
}
}

LL pow_MOD(LL n, LL m) {//快速幂
LL ans = 1;
while (m) {
if (m & 1)ans = (ans * n) % MOD;
n = (n * n) % MOD;
m >>= 1;
}
return ans;
}

int main() {
LL n, m, k;
get_combinations();
scanf("%lld%lld%lld", &n, &m, &k);
for (LL a = 1; a <= n; a++) {//确定在第a列取b个数会对后面的影响
for (LL b = 0; b <= n; b++) {//当m%n后剩下的数仍够a则会影响后面m/n+1列,否则影响m/n列
Z[a][b] = pow_MOD(C
[b], m / n +  + (m % n >= a));
}
}
dp[0][0] = 1;
for (LL a = 1; a <= n; a++) {//对于第a行时一共确定了b个点的状态
for (LL b = 0; b <= min(k, n * a); b++) {
for (LL c = 0; c <= min(b, n); c++) {
dp[a][b] = (dp[a][b] + dp[a - 1][b - c] * Z[a][c]) % MOD;
}
}
}
printf("%lld\n", dp
[k]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces dp