版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89788875
【题目链接】
【思路要点】
- 考虑计算 号操作不超过 次的方案数。
- 它应当等于 个 的倍数、 个 的倍数、 个 的倍数、……、 个 的倍数总和为 的方案数,从高位向低位 ,那么第 位可以填数的位置数应当为 ,保留余数不超过 的状态即可。
- 上述做法需要进行 次 ,但压位后已经可以通过。
- 注意到 在 较小时只与 有关, 较大时的 值就是隔板法形成的组合数,可以避免进行 次 ,改为从低位向高位进行一次 。
- 不计高精度运算的时间复杂度为 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 55; const int MAXNK = 605; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } const int MAXP = 205, P = 1e9; struct INT { int len, a[MAXP]; INT () { len = 1; memset(a, 0, sizeof(a)); } INT (int num) { assert(num < P); len = 1; memset(a, 0, sizeof(a)); a[0] = num; } }; bool operator < (const INT &x, const INT &y) { if (x.len < y.len) return true; if (x.len > y.len) return false; for (int i = x.len - 1; i >= 0; i--) { if (x.a[i] < y.a[i]) return true; if (x.a[i] > y.a[i]) return false; } return false; } bool operator > (const INT &x, const INT &y) { if (x.len > y.len) return true; if (x.len < y.len) return false; for (int i = x.len - 1; i >= 0; i--) { if (x.a[i] > y.a[i]) return true; if (x.a[i] < y.a[i]) return false; } return false; } bool operator <= (const INT &x, const INT &y) { if (x.len < y.len) return true; if (x.len > y.len) return false; for (int i = x.len - 1; i >= 0; i--) { if (x.a[i] < y.a[i]) return true; if (x.a[i] > y.a[i]) return false; } return true; } bool operator >= (const INT &x, const INT &y) { if (x.len > y.len) return true; if (x.len < y.len) return false; for (int i = x.len - 1; i >= 0; i--) { if (x.a[i] > y.a[i]) return true; if (x.a[i] < y.a[i]) return false; } return true; } bool operator == (const INT &x, const INT &y) { if (x.len != y.len) return false; for (int i = x.len - 1; i >= 0; i--) if (x.a[i] != y.a[i]) return false; return true; } bool operator != (const INT &x, const INT &y) { if (x.len != y.len) return true; for (int i = x.len - 1; i >= 0; i--) if (x.a[i] != y.a[i]) return true; return false; } INT operator + (const INT &x, const INT &y) { INT res; res.len = max(x.len, y.len) + 1; for (int i = 0; i < res.len; i++) { res.a[i] += x.a[i] + y.a[i]; if (res.a[i] >= P) { res.a[i + 1] += res.a[i] / P; res.a[i] %= P; } } while (res.len >= 2 && res.a[res.len - 1] == 0) res.len--; return res; } INT operator += (INT &x, const INT &y) { x = x + y; return x; } INT operator - (const INT &x, const INT &y) { INT res; assert(x >= y); res.len = x.len; for (int i = 0; i < res.len; i++) { res.a[i] += x.a[i] - y.a[i]; if (res.a[i] < 0) { res.a[i + 1] += res.a[i] / P; res.a[i] %= P; if (res.a[i] < 0) { res.a[i + 1] -= 1; res.a[i] += P; } } } while (res.len >= 2 && res.a[res.len - 1] == 0) res.len--; return res; } INT operator -= (INT &x, const INT &y) { x = x - y; return x; } INT operator * (const INT &x, const INT &y) { INT res; res.len = x.len + y.len; static long long tres[MAXP]; memset(tres, 0, sizeof(tres)); for (int i = 0; i < x.len; i++) for (int j = 0; j < y.len; j++) { long long tmp = 1ll * x.a[i] * y.a[j]; tres[i + j] += tmp % P; tres[i + j + 1] += tmp / P; } for (int i = 0; i < res.len; i++) { tres[i + 1] += tres[i] / P; res.a[i] = tres[i] % P; } while (res.len >= 2 && res.a[res.len - 1] == 0) res.len--; return res; } INT operator *= (INT &x, const INT &y) { x = x * y; return x; } INT operator / (const INT &x, const int &y) { INT res; ll rem = 0; res.len = x.len; for (int i = x.len - 1; i >= 0; i--) { rem += x.a[i]; res.a[i] = rem / y; rem = rem % y * P; } while (res.len >= 2 && res.a[res.len - 1] == 0) res.len--; return res; } INT operator /= (INT &x, const int &y) { x = x / y; return x; } int operator % (const INT &x, const int &y) { int ans = x.a[x.len - 1] % y; for (int i = x.len - 2; i >= 0; i--) ans = (1ll * P * ans + x.a[i]) % y; return ans; } INT operator %= (INT &x, const int &y) { x = x % y; return x; } void print(const INT &x) { printf("%d", x.a[x.len - 1]); for (int i = x.len - 2; i >= 0; i--) printf("%09d", x.a[i]); printf("\n"); } INT f[MAXN][MAXNK]; INT dp[MAXN][MAXNK]; INT n, res[MAXN]; int k, Log, a[MAXN]; void getdp() { f[0][0] = 1; for (int i = 1; i <= Log + 2; i++) for (int j = 0; j <= i * (k - 1); j++) for (int l = 0; l <= k - 1 && l <= j; l++) f[i][j] += f[i - 1][j - l]; dp[0][0] = 1; for (int i = 0; i <= Log - 1; i++) for (int j = 0; j <= (i + 2) * k; j++) { for (int l = 0; l <= (i + 2) * (k - 1) && l <= j; l++) if ((j - l) * k + a[i] <= (i + 2) * k) dp[i + 1][j] += dp[i][(j - l) * k + a[i]] * f[(i + 2)][l]; } } INT binom(INT a, int b) { INT ans = 1; int tmp = 1; for (int i = 1; i <= b; i++) ans *= (a - (i - 1)); for (int i = 1; i <= b; i++) { if (1ll * tmp * i >= P) ans /= tmp, tmp = i; else tmp *= i; } return ans / tmp; } INT getans(int n) { INT ans = 0, lft = 0; for (int i = Log; i >= n; i--) lft = lft * k + a[i]; for (int i = 0; i <= (n + 2) * k && i <= lft; i++) if ((lft - i) % k == 0) ans += dp[n][i] * binom((lft - i) / k + n + 1, n + 1); return ans; } int main() { read(k), read(n); Log = 0; while (n != 0) { a[++Log] = n % k; n /= k; } getdp(); INT last = 1; for (int i = 0; i <= Log - 1; i++) { res[i] = getans(i); print(res[i] - last); last = res[i]; } return 0; }