P1708 题解

传送门

观察到值域 n7,k100 的范围较小,且含有较多重复内容, 因此考虑打表。

打表的思路也很简单:使用一个三重循环,最外层为 n,中层为 k,最内层枚举 1107 中的每个数,将答案记录在一个二维数组 ans 中,最后输出到文件,复制进代码中,打表完成。

完整代码如下:

//by Cuset_Nekomusume 20240310
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef long double ld;
//an数组为打好的表,ans为打表时的暂存数组。
int ans[8];
int an[7][101] = {{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
{0, 2, 5, 9, 14, 20, 27, 35, 44, 54, 63, 71, 78, 84, 89, 93, 96, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99},
{0, 3, 9, 19, 34, 55, 83, 119, 164, 219, 282, 351, 424, 499, 574, 647, 716, 779, 834, 879, 915, 943, 964, 979, 989, 995, 998, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999, 999},
{0, 4, 14, 34, 69, 125, 209, 329, 494, 714, 996, 1344, 1759, 2239, 2779, 3371, 4004, 4664, 5334, 5994, 6627, 7219, 7759, 8239, 8654, 9002, 9284, 9504, 9669, 9789, 9873, 9929, 9964, 9984, 9994, 9998, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999},
{0, 5, 20, 55, 125, 251, 461, 791, 1286, 2001, 2997, 4337, 6082, 8287, 10997, 14243, 18038, 22373, 27213, 32493, 38124, 43999, 49999, 55999, 61874, 67505, 72785, 77625, 81960, 85755, 89001, 91711, 93916, 95661, 97001, 97997, 98712, 99207, 99537, 99747, 99873, 99943, 99978, 99993, 99998, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999},
{0, 6, 27, 83, 209, 461, 923, 1715, 3002, 5004, 8001, 12333, 18395, 26627, 37499, 51491, 69068, 90650, 116577, 147069, 182196, 221858, 265775, 313487, 364364, 417626, 472373, 527625, 582372, 635634, 686511, 734223, 778140, 817802, 852929, 883421, 909348, 930930, 948507, 962499, 973371, 981603, 987665, 991997, 994994, 996996, 998283, 999075, 999537, 999789, 999915, 999971, 999992, 999998, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999, 999999},
{0, 7, 35, 119, 329, 791, 1715, 3431, 6434, 11439, 19440, 31767, 50135, 76679, 113969, 164999, 233144, 322079, 435654, 577719, 751914, 961439, 1208819, 1495679, 1822544, 2188679, 2591984, 3028959, 3494754, 3983319, 4487634, 4999999, 5512364, 6016679, 6505244, 6971039, 7408014, 7811319, 8177454, 8504319, 8791179, 9038559, 9248084, 9422279, 9564344, 9677919, 9766854, 9834999, 9886029, 9923319, 9949863, 9968231, 9980558, 9988559, 9993564, 9996567, 9998283, 9999207, 9999669, 9999879, 9999963, 9999991, 9999998, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999, 9999999}};
//get1~7为获取一个数每一位的函数,很简单,对吧awa
inline int get1(int x) {
return x % 10;
}
inline int get2(int x) {
return x / 10 % 10;
}
inline int get3(int x) {
return x / 100 % 10;
}
inline int get4(int x) {
return x / 1000 % 10;
}
inline int get5(int x) {
return x / 10000 % 10;
}
inline int get6(int x) {
return x / 100000 % 10;
}
inline int get7(int x) {
return x / 1000000 % 10;
}
//init1~7为打表的暴力循环函数,比较冗长,不过好理解
inline void init1(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
}
inline void init2(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
//此处循环仅处理了对应位数的答案,所以要求一遍前缀和,下同。
}
inline void init3(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
for (int i = 100; i <= 999; i++) {
if (get1(i) + get2(i) + get3(i) <= k) ans[3]++;
}
ans[3] += ans[2];
}
inline void init4(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
for (int i = 100; i <= 999; i++) {
if (get1(i) + get2(i) + get3(i) <= k) ans[3]++;
}
ans[3] += ans[2];
for (int i = 1000; i <= 9999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) <= k) ans[4]++;
}
ans[4] += ans[3];
}
inline void init5(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
for (int i = 100; i <= 999; i++) {
if (get1(i) + get2(i) + get3(i) <= k) ans[3]++;
}
ans[3] += ans[2];
for (int i = 1000; i <= 9999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) <= k) ans[4]++;
}
ans[4] += ans[3];
for (int i = 10000; i <= 99999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) <= k) ans[5]++;
}
ans[5] += ans[4];
}
inline void init6(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
for (int i = 100; i <= 999; i++) {
if (get1(i) + get2(i) + get3(i) <= k) ans[3]++;
}
ans[3] += ans[2];
for (int i = 1000; i <= 9999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) <= k) ans[4]++;
}
ans[4] += ans[3];
for (int i = 10000; i <= 99999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) <= k) ans[5]++;
}
ans[5] += ans[4];
for (int i = 100000; i <= 999999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) + get6(i) <= k) ans[6]++;
}
ans[6] += ans[5];
}
inline void init7(int k) {
for (int i = 1; i <= 9; i++) {
if (i <= k) ans[1]++;
}
for (int i = 10; i <= 99; i++) {
if (get1(i) + get2(i) <= k) ans[2]++;
}
ans[2] += ans[1];
for (int i = 100; i <= 999; i++) {
if (get1(i) + get2(i) + get3(i) <= k) ans[3]++;
}
ans[3] += ans[2];
for (int i = 1000; i <= 9999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) <= k) ans[4]++;
}
ans[4] += ans[3];
for (int i = 10000; i <= 99999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) <= k) ans[5]++;
}
ans[5] += ans[4];
for (int i = 100000; i <= 999999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) + get6(i) <= k) ans[6]++;
}
ans[6] += ans[5];
for (int i = 1000000; i <= 9999999; i++) {
if (get1(i) + get2(i) + get3(i) + get4(i) + get5(i) + get6(i) + get7(i) <= k) ans[7]++;
}
ans[7] += ans[6];
}
signed main() {
// freopen("t.out", "w", stdout);
// for (int i = 1; i <= 7; i++) {
// for (int j = 1; j <= 100; j++) {
// memset(ans, 0, sizeof(ans));
// if (i == 1) init1(j);
// if (i == 2) init2(j);
// if (i == 3) init3(j);
// if (i == 4) init4(j);
// if (i == 5) init5(j);
// if (i == 6) init6(j);
// if (i == 7) init7(j);
// printf("%lld, ", ans[i]);
// }
// printf("\n");
// }
int t;
cin >> t;
int n, k;
for (int i = 1; i <= t; i++) {
cin >> n >> k;
printf("%lld\n", an[n - 1][k]);
}
return 0;
}

代码中,main 函数注释掉的一段为打表部分,未注释掉的为输出部分。打表部分用时 5.995s,还是很快的。因此,在比赛时如果题目值域小,打表也不失为一种好的方式。

完结撒花awa~

本文作者:CusetVoidAldehyde

本文链接:https://www.cnblogs.com/CusetVoidAldehyde/p/18269098

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Cuset_VoidAldehyde  阅读(10)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起