一.题面:点这里

二.思路:

看到 \(P\) 的范围,以及整除性,我们自然的想到考虑按模 \(P\) 分类。然后观察这个超长数本身的特性,一般情况下它可以理解为出现一段相同的数后出现一个分界线,然后加上一个很小的数 \(t\) 。所以我灵光一现,就考虑把这个数拆成若干个 \(000...011...1111\) 的形式的数相加,注意此处的写法虽然不规范含有前导零,但是方便理解。那么每一个 \(01\) 分界点也就是我们数里的区间断点。那么经常做模运算相关题目的小朋友们都知道大部分情况下模运算相关具备周期性,事实上这道题也如此,我们如果定义 \(f_i\) 表示长度为 \(i\) 的 \(1111...11\) 的数对 \(P\) 取模的值,显然有递推式:

\[f_i = (10 \times f_{i-1} + 1)\mod P
\]

那么根据鸽巢原理,在最多第 \(P + 1\) 次的迭代中会出现重复的值,那么在模 \(P\) 的意义下就出现了循环。

这个结论启发我们定义一个辅助数组 \(g_i\) ,表示模数为 \(i\) 的形如 \(11...11\) 的数有多少。因为有了循环,我们计算这个数列极其高效的,我们对于较大的 \(P\) 我们可以考虑暴力把循环出现之前的部分处理掉,然后用数学原理处理循环内部的值。

我们现在考虑计数答案,一个自然的想法是定义 \(F(k,r)\) 表示选了 \(k\) 个数,模意义下和为 r 的方案数,但是发现转移是极其困难的,原因在于会出现重复并不好递推处理,比如说对于 \(F(k,2r\mod P)\) 包含两个状态 \(\{f_a,f_b\},\{f_a,f_a\}\),然后下一次转移到 \(F(k+1,3r\mod P)\) 时往第一个状态中加入 \(f_a\) 和往第二个状态中加入 \(f_b\) 的情况实际是一样的,因为我们的长度为 \(n\) 的数时单调递增的,所以所有数的排列方式是由单调性唯一确定的。但是我们发现刚才的过程实际上是产生了排列,而我们从最终结果来看是只需要一个组合的贡献。

所以我们去考虑对状态的定义增加限制,我们定义 \(F(k,r,t)\) 表示模数类为 \([0,t-1]\) 的数已经被考虑完,考虑选取第 \(t\) 类数且最终选了 \(k\) 个数,和的模数为 \(r\) 的方案数,这样定义的好处在于我们使得每一类的选取是符合我们预期限制的,因为不同类之间不会存在冲突。可以得到最后的转移方程为:

\[F(k,(r+(l\times t))\mod P,t+1)=\dbinom{g_t + l - 1}{l}\times\sum_l F(k-l,r,t)
\]

这里的组合数是怎么来的呢,考虑集合 \(g_t\) 中的元素,他们虽然在模意义下是无区别的,但是对于原数是不同的方案,这个问题等价于集合中有 \(g_t\) 个元素,每种元素有无穷多种,现要选出 \(l\) 个元素的组合,求有多少种方案。这个问题看似很难解决,但是我们可以换一种思考方式,原问题等价于,我们有 \(l\) 个小球,小球本身没有区别,现有 \(g_t\) 个盒子,盒子两两不同,将小球放入盒子后,小球会被赋予种类,盒子可以空,求有多少种组合方案。这是一个经典的小球盒子问题,无论用隔板法或者多重集合的相关知识都可以证明答案就是 \(\dbinom{g_t + l - 1}{l}\) 。

此外我们需要注意的是,原本的数中一定可以拆出来一种全是 \(1\) 没有 \(0\) 的方案,我们需要求出这个值赋予其初始值在dp的初始值中。

三.Code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#define int long long
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch > '9' || ch < '0'){if(ch == '-'){f = -1;}ch = getchar();}
while(ch >= '0'&&ch <= '9'){x = x * 10 + ch - 48; ch = getchar();}
return x * f;
} const int MP = 500 + 10, MOD = 999911659;
int f[MP][11][MP], g[MP], inv[11], C[505][11], n, P, sum, pos[MP]; signed main() {
n = read(), P = read();
inv[0] = inv[1] = 1; if (n <= P) {
for (int i = 1; i <= n; ++i) {
sum = (sum * 10 + 1) % P;
++g[sum];
}
}
else {
int tot = 1 % P, len, loc;
for (int i = 1; i <= P + 1; ++i) {
if (pos[tot]) {
loc = pos[tot], len = i - loc;
break;
}
pos[tot] = i, ++g[tot], tot = (tot * 10 + 1) % P;
} for (int i = 0; i < P; ++i) {
if (pos[i] && pos[i] >= loc) {
g[i] += ((n - pos[i]) / len) % MOD;
if ((pos[i] - loc + 1) % len == (n - loc + 1) % len) sum = i;
}
}
} for (int i = 2; i <= 9; ++i) inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD; for (int i = 0; i < P; ++i) {
C[i][0] = 1;
if (!g[i]) continue;
for (int j = 1; j < 9; ++j, g[i] = (g[i] + 1) % MOD)
C[i][j] = C[i][j - 1] * g[i] % MOD * inv[j] % MOD;
} f[0][0][sum] = 1;
for (int i = 0; i < P; ++i) {
for (int j = 0; j < P; ++j) {
for (int k = 0; k < 9; ++k) {
for (int t = 0; t < 9 - k; ++t) {
(f[i + 1][t + k][(j + t * i) % P] += f[i][k][j] * C[i][t] % MOD) % MOD;
}
}
}
} int ans = 0;
for (int i = 0; i < 9; ++i) ans = (ans + f[P][i][0]) % MOD; printf("%lld", ans);
return 0;
}

洛谷P2481 [SDOI2010] 代码拍卖会 题解的更多相关文章

  1. 洛谷 P2481 [SDOI2010]代码拍卖会

    洛谷 这大概是我真正意义上的第一道黑题吧! 自己想出了一个大概,状态转移方程打错了一点点,最后还是得看题解. 一句话题意:求出有多少个\(n\)位的数,满足各个位置上的数字从左到右不下降,且被\(p\ ...

  2. 洛谷 P2481 [SDOI2010]代码拍卖会(背包+隔板法)

    题面传送门 题意: 给出 \(n,p\),求有多少 \(n\) 位数 \(X=a_1a_2a_3\dots a_n\) 满足: 该 \(n\) 位数不含前导零 \(a_i \leq a_{i+1}\) ...

  3. luogu P2481 [SDOI2010]代码拍卖会

    luogu 题目中的那个大数一定是若干个1+若干个2+若干个3...+若干个9组成的,显然可以转化成9个\(\underbrace {111...1}_{a_i个1}(0\le a_1\le a_2\ ...

  4. SDOI2010代码拍卖会 (计数类DP)

    P2481 SDOI2010代码拍卖会 $ solution: $ 这道题调了好久好久,久到都要放弃了.洛谷的第五个点是真的强,简简单单一个1,调了快4个小时! 这道题第一眼怎么都是数位DP,奈何数据 ...

  5. 洛谷P1783 海滩防御 分析+题解代码

    洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...

  6. 洛谷P4047 [JSOI2010]部落划分题解

    洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...

  7. 02题解-洛谷 P2395 BBCode转换Markdown 题解

    洛谷 P2395 BBCode转换Markdown 题解 题目传送门: here. 一道毒瘤的大模拟,给了你一部分的 BBCode 和 Markdown 语法,叫你转换.如下表: BBCode Mar ...

  8. 洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)

    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1311990 原题地址:洛谷P1155 双栈排序 ...

  9. 洛谷10月月赛II题解

    [咻咻咻] (https://www.luogu.org/contestnew/show/11616) 令人窒息的洛谷月赛,即将参加NOIp的我竟然只会一道题(也可以说一道也不会),最终145的我只能 ...

  10. BZOJ2527 & 洛谷3527:[Poi2011]Meteors——题解

    +++++++++++++++++++++++++++++++++++++++++++ +本文作者:luyouqi233. + +欢迎访问我的博客:http://www.cnblogs.com/luy ...

随机推荐

  1. 高德地图 MCP,可用 Java SolonMCP 接入(支持 java8, java11, java17, java21)

    1.MCP技术概述 1.1 什么是 MCP MCP (Model Control Protocol) 是一种允许大模型与外部工具交互的协议,高德地图基于此协议提供了地图服务能力,使 AI 大模型能够直 ...

  2. 202402 湖北武汉 4D3N3P

    202402 湖北武汉 4D3N3P D0 / 10 杭州出发 普速列车25T Z47 杭州-武昌 城站22:22开 第3候车室 这趟列车是武汉局"华东三直"中的其中一列,另外两列 ...

  3. frp实现内网穿透访问内网多台Linux服务器

    本文主要记录笔者在使用frp实现内网穿透访问内网多台Linux服务器的全过程,包括公网服务器的配置.frp服务端.客户端的下载与配置,以及配置systmctl来实现系统级启停frp,并记录我遇到的一些 ...

  4. Springboot笔记<5>静态资源访问

    静态资源访问 静态资源目录 请求进来,先去找Controller看能不能处理.不能处理的所有请求又都交给静态资源处理器.静态资源也找不到则响应404页面.如果静态目录中存在a.png,访问localh ...

  5. MinHook 对.NET底层的 SendMessage 拦截真实案例反思

    一:背景 1. 讲故事 上一篇我们说到了 minhook 的一个简单使用,这一篇给大家分享一个 minhook 在 dump 分析中的实战,先看下面的线程栈. 0:044> ~~[138c]s ...

  6. Druid监控页面配置

    springboot的yml配置文件添加如下配置: spring: # 数据库连接相关配置 datasource: druid: filters: stat,wall stat-view-servle ...

  7. 搭建第一个vue项目

    第一:你需要在Windows环境下面搭建vue的开发环境,具体可参考如下的地址: https://www.cnblogs.com/zhaomeizi/p/8483597.html 第二:当你搭建好之后 ...

  8. 有知道CAE软件Hypermesh的配置要求吗?

    Altair的Hypermesh是一款先进的有限元分析软件,用于高效地处理和模拟复杂的三维几何形状.作为一款仿真软件,Hypermesh的CPU和GPU配置是非常重要的. 首先,对于Hypermesh ...

  9. 使用GcExcel .NET将Excel导出为PDF

    使用GcExcel .NET将Excel导出为PDF 引言 在企业级应用开发中,经常需要将Excel数据导出为PDF格式以便于共享和打印.GrapeCity Documents for Excel(简 ...

  10. stm32 单片机主要优点有哪些?

    STM32单片机主要优点有哪些?一个十年嵌入式老兵的深度剖析 看到这个问题,我不禁想起了十年前那个拿着STM32开发板发愁的自己.作为一个本硕都是机械专业,却误打误撞进入嵌入式领域的过来人,从24岁在 ...