0%

noip2016提高组组合数问题

[题目图片]
(https://www.luogu.com.cn/problem/P2822)

30pts

直接上 long long, 暴力套公式…
代码就不给出了……

90pts

kC(i,j)C(i,j) mod k=0k | C(i, j) \Leftrightarrow C(i, j)\ mod\ k = 0

知道怎么做了吧

直接递推组合数并对 k 取模,判断这是不是0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 2e3 + 10;
int t, k;
int n, m;
int dp[N][N];

void build()
{
dp[0][0] = 1;
dp[1][0] = dp[1][1] = 1;
for(int i = 1; i <= 2000; i++)
{
dp[i][0] = 1;
for(int j = 1; j <= i; j++)
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % k;
}
}

int main(void)
{
cin >> t >> k;
build();
for (int cse = 1; cse <= t; cse++)
{
scanf("%d%d", &n, &m);
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= min(i, m); j++)
{
if (!dp[i][j])
ans++;
}
printf("%d\n", ans);
}
}

100分

很多人看到这里已经知道了。。
没错,二维前缀和!
这里提供一种计算的新方法(看代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 2e3 + 10;
int t, k;
int n, m;
int dp[N][N];
int s[N][N];

void build()
{
dp[0][0] = 1;
dp[1][0] = dp[1][1] = 1;
for(int i = 1; i <= 2000; i++)
{
dp[i][0] = 1;
for(int j = 1; j <= i; j++)
{
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % k;
if(!dp[i][j]) s[i][j] = 1;
}
}
for(int i = 1; i <= 2000; i++) for(int j = 1; j <= 2000; j++) s[i][j] += s[i][j - 1];
for(int i = 1; i <= 2000; i++) for(int j = 1; j <= 2000; j++) s[i][j] += s[i - 1][j];
}

int main(void)
{
cin >> t >> k;
build();
for (int cse = 1; cse <= t; cse++)
{
scanf("%d%d", &n, &m);
// int ans = 0;
// for (int i = 1; i <= n; i++)
// for (int j = 1; j <= min(i, m); j++)
// {
// if (!dp[i][j])
// ans++;
// }
printf("%d\n", s[n][m]);
}
}

欢迎关注我的其它发布渠道