移动端 Banners
P6669 - [清华集训2016] 组合数问题 题解
579 字
3 分钟
P6669 - [清华集训2016] 组合数问题 题解
Done
您已获得最佳的阅读体验!
题目地址:P6669
看到超大组合数对质数取模首先考虑朴素
其中第一项可以继续递归。但是这里要涉及到
其中
如果一个数要是
#include <bits/stdc++.h>
#define N 62#define MOD 1000000007using namespace std;
typedef long long ll;
int numN[N], numM[N];ll f[N][2][2][2][2];int k;
ll dfs(int pos, bool valid, bool limitN, bool limitM, bool limitI) {// 当前位 是否已合法 i顶到上界n j顶到上界m j顶到上界i if (pos < 0) return valid; if (f[pos][valid][limitN][limitM][limitI] >= 0) return f[pos][valid][limitN][limitM][limitI]; // 记忆化搜索 ll sum = 0; for (int i = 0; i <= (limitN ? numN[pos] : k - 1); i++) { // 枚举 i 在这一位上填的数字 for (int j = 0; j <= min((limitM ? numM[pos] : k - 1), (limitI ? i : k - 1)); j++) { // 枚举 j 在这一位上填的数字,注意需要满足 j 不超过 i 和 m 的最小值 sum = (sum + dfs(pos - 1, valid | (j > i), limitN & (i == numN[pos]), limitM & (j == numM[pos]),limitI & (i == j))) % MOD; } } f[pos][valid][limitN][limitM][limitI] = sum; return sum;}
ll calc(ll n, ll m) { memset(numN, 0, sizeof numN); memset(numM, 0, sizeof numM); memset(f, -1, sizeof f);
// 进制分解 int size1 = 0, size2 = 0; ll tmp1 = n, tmp2 = m; while (tmp1) { numN[size1++] = tmp1 % k; tmp1 /= k; } while (tmp2) { numM[size2++] = tmp2 % k; tmp2 /= k; } return dfs(max(size1, size2) - 1, false, true, true, true);}
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
memset(f, -1, sizeof f);
int t; cin >> t >> k; while (t--) { ll n, m; cin >> n >> m; cout << calc(n, m) << endl; } return 0;} P6669 - [清华集训2016] 组合数问题 题解
https://justpureh2o.cn/articles/6669/ 最后更新于 2024-09-28,距今已过 539 天
部分内容可能已过时
相关文章 智能推荐
1
数论补完计划 Part5 组合计数
oi算法 2024-09-25
2
数论补完计划 Part1 基本定理、质数与约数
oi算法 2024-09-14
3
CF 755D - PolandBall and Polygon 题解
题解 2024-11-27
4
P3571 [POI2014] - Supercomputer 题解
题解 2024-08-25
5
SP15648 [APIO10A] - Commando 题解
题解 2024-07-25
随机文章 随机推荐