[
]
(https://www.luogu.com.cn/problem/P2822)
30pts
直接上 long long, 暴力套公式…
代码就不给出了……
90pts
k∣C(i,j)⇔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); printf("%d\n", s[n][m]); } }
|