本帖最后由 guosl 于 2022-2-10 11:48 编辑
本题所涉及的数比较大故在程序中用了大数库mpir。/*
答案:51161058134250
耗时:0.000191秒
*/
#include <iostream>
#include <mpir.h>
#include <omp.h>
using namespace std;
int f[10][10];//f[i][j]为长度是i且最后一个数的值是j的严格递增序列的个数
int g[11][10];//g[i][j]为长度是i且最后一个数的值是j的严格递减序列的个数
int main(void)
{
double d = omp_get_wtime();
for (int i = 1; i < 10; ++i)
{
f[1][i] = 1;//长度为1的序列只有一个
g[1][i] = 1;//长度为1的序列只有一个
}
for (int i = 2; i < 10; ++i)
{
for (int j = 1; j < 10; ++j)
{
for (int k = 1; k < j; ++k)
f[i][j] += f[i - 1][j - k];
}
}
for (int i = 2; i <= 10; ++i)
{
for (int j = 1; j < 10; ++j)
{
for (int k = 1; k <= j; ++k)
g[i][j - k] += g[i - 1][j];
}
}
mpz_t zSum, t;
mpz_inits(zSum, t, 0);
mpz_set_ui(zSum, 99);
for (int w = 3; w <= 100; ++w)//对数字位数进行枚举
{
//计算递增数的个数
for (int k = 1; k < 9; ++k)//枚举跳跃点的个数
{
if (k > w - 1)
break;
mpz_bin_uiui(t, w - 1, k);//跳跃点的选取方式数
int s = 0;
//此时跳跃数组的长度为k+1
for (int a = 1; a < 10; ++a)//计算具体的递增数组的选取方式数
s += f[k + 1][a];
mpz_mul_si(t, t, s);
mpz_add(zSum, zSum, t);
}
//计算递减数的个数
for (int k = 1; k <= 9; ++k)//枚举跳跃点的个数
{
if (k > w - 1)
break;
mpz_bin_uiui(t, w - 1, k);//跳跃点的选取方式数
int s = 0;
//此时跳跃数组的长度为k+1
for (int a = 0; a < 10; ++a)//计算具体的递减数组的选取方式数
s += g[k + 1][a];
mpz_mul_si(t, t, s);
mpz_add(zSum, zSum, t);
}
mpz_add_ui(zSum, zSum, 9);//加上跳跃数为0的数的个数
}
d = omp_get_wtime() - d;
gmp_printf("%Zd\n%lf\n", zSum, d);
mpz_clears(zSum, t, 0);
return 0;
}
|