题面传送门

题意:

给出 \(n,p\),求有多少 \(n\) 位数 \(X=a_1a_2a_3\dots a_n\) 满足:

  1. 该 \(n\) 位数不含前导零
  2. \(a_i \leq a_{i+1}\)
  3. \(X\) 为 \(p\) 的倍数。

答案对 \(998244353\) 取模。

\(1 \leq n \leq 10^{18}\),\(1 \leq p \leq 500\)。

CSP 之前做的了,隔了好久才把题解补了。。。

本题的突破口在于怎样处理 \(a_i \leq a_{i+1}\) 这个条件。

我们不妨进行一个转化:每次加一个全是 \(1\) 的后缀,最多可以加 \(9\) 次,这样就能保证得到的数一定满足条件 2。

又由于 \(X\) 不能含前导零,所以我们加的后缀中必须有一个是长度 \(n\) 的后缀。

于是我们有了优秀的 \(n^8\) 的做法,可以拿到 10 分的好成绩。

但仔细观察就可以发现,每个后缀 \(111...11\) 对 \(p\) 取模的余数呈周期分部。

例如当 \(p=12\) 的时候,各后缀模 \(p\) 的余数分别为:\(1,11,9,7,11,9,7,11,...\)

不难看出除了 \(1\) 以外每三个一循环。

有了这个发现,我们就可以将这 \(n\) 个后缀分为三类:

  1. 还没进循环节
  2. 在完整的循环节中
  3. 在最后多出的部分中

证明可用扩展欧拉定理。

记 \(cnt_m\) 为模 \(p\) 余 \(m\) 的后缀数。分类讨论可以在 \(\mathcal O(p)\) 的时间内求出 \(cnt\)。

接下来就可以 \(dp\) 了。\(dp[i][j][k]\) 表示选择了余数为 \(0\) 到 \(i\) 的后缀共 \(j\),它们的和模 \(p\) 余 \(k\) 的方案数。

转移的时候枚举选择多少个余数为 \(i\) 的后缀,记为 \(s\)。

由于可以重复选择,这一部分的方案数可以用隔板法求,\(\dbinom{cnt_i+s-1}{s}\)。

最后别忘了我们必须选择长度为 \(n\) 的后缀,所以答案为 \(\sum\limits_{i=0}^8dp[p-1][i][(p-pn)\mod m]\),其中 \(pn\) 为长度为 \(n\) 的后缀对 \(p\) 取模的结果。

别忘了特判 \(p=1\),卡了我很久。。。。。。

综上,这是一道非常不错的综合题。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define mp make_pair
#define int long long
typedef pair<int,int> pii;
typedef long long ll;
const ll MOD=999911659;
ll n;
int p,a[505];
int vis[505];
ll cnt[505];
ll dp[505][10][505];
inline ll qpow(ll x,ll e){
ll ans=1;
while(e){
if(e&1) ans=ans*x%MOD;
x=x*x%MOD;e>>=1;
}
return ans;
}
ll inv[505];
inline ll getc(ll x,ll y){
ll ans=1;
for(int i=x;i>=x-y+1;i--) ans=ans*(i%MOD)%MOD;
for(int i=1;i<=y;i++) ans=ans*inv[i]%MOD;
return ans;
}
inline void inc(ll &x,ll y){
x+=y;if(x>=MOD) x-=MOD;
}
signed main(){
scanf("%lld%lld",&n,&p);
for(int i=1;i<=10;i++) inv[i]=qpow(i,MOD-2);
int cur=1;vis[cur]=1%p;
int len1,len2;a[1]=1%p;
for(int i=2;i<=1000;i++){
cur=(cur*10+1)%p;a[i]=cur;
if(vis[cur]){
len1=vis[cur]-1;len2=i-vis[cur];
break;
}
vis[cur]=i;
}
if(n<=len1) for(int i=1;i<=n;i++) cnt[a[i]]++;
else{
ll cyc=(n-len1)/len2;
ll rem=(n-len1)%len2;
for(int i=1;i<=len1;i++) cnt[a[i]]++;
for(int i=len1+1;i<=len1+len2;i++) cnt[a[i]]+=cyc;
for(int i=len1+1;i<=len1+rem;i++) cnt[a[i]]++;
}
for(int i=0;i<9;i++){
dp[0][i][0]=getc(cnt[0]+i-1,i)%MOD;
}
for(int i=0;i<p-1;i++) for(int j=0;j<9;j++) for(int k=0;k<p;k++){
for(int l=0;l+j<9;l++){
inc(dp[i+1][l+j][(k+l*(i+1))%p],dp[i][j][k]*getc(cnt[i+1]+l-1,l)%MOD);
}
}
int gn;
if(n<=len1) gn=a[n];
else if((n-len1)%len2==0) gn=a[len1+len2];
else gn=a[len1+(n-len1)%len2];
ll ans=0;
for(int i=0;i<9;i++) inc(ans,dp[p-1][i][(p-gn)%p]);
printf("%lld\n",ans);
return 0;
}
/*
1000000000 499
1000000000000000000 1
2 1
*/

洛谷 P2481 [SDOI2010]代码拍卖会(背包+隔板法)的更多相关文章

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

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

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

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

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

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

  4. 洛谷 P2014 选课(树形背包)

    洛谷 P2014 选课(树形背包) 思路 题面:洛谷 P2014 如题这种有依赖性的任务可以用一棵树表示,因为一个儿子要访问到就必须先访问到父亲.然后,本来本题所有树是森林(没有共同祖先),但是题中的 ...

  5. 洛谷P4525 【模板】自适应辛普森法1与2

    洛谷P4525 [模板]自适应辛普森法1 与P4526[模板]自适应辛普森法2 P4525洛谷传送门 P4525题目描述 计算积分 结果保留至小数点后6位. 数据保证计算过程中分母不为0且积分能够收敛 ...

  6. BZOJ1925或洛谷2467 [SDOI2010]地精部落

    BZOJ原题链接 洛谷原题链接 先讲下关于波动数列的\(3\)个性质. 性质\(1\):对于数列中的每一对\(i\)和\(i + 1\),若它们不相邻,那么交换这两个数形成的依旧是一个波动数列. 性质 ...

  7. 洛谷 P4389: 付公主的背包

    题目传送门:洛谷 P4389. 题意简述: 有 \(n\) 个物品,每个物品都有无限多,第 \(i\) 个物品的体积为 \(v_i\)(\(v_i\le m\)). 问用这些物品恰好装满容量为 \(i ...

  8. 洛谷 P2467 [SDOI2010]地精部落

    洛谷 我讲的应该没有这个[https://www.luogu.org/blog/user55639/solution-p2467]清楚. 贴个代码算了: #include <bits/stdc+ ...

  9. 洛谷P2468 [SDOI2010]粟粟的书架

    来了来了,随便拽一道题写题解[大雾] 最近发现自己基础奇差于是开始复习之前学过的东西,正好主席树我几乎完全没学会,然后打开洛谷试炼场… 发现了这么一道二合一的题. 这道题其实分成两个部分,前50%是一 ...

随机推荐

  1. rocketMQ(一)基础环境

    一.安装: http://rocketmq.apache.org/dowloading/releases/ https://www.apache.org/dyn/closer.cgi?path=roc ...

  2. 看动画学算法之:队列queue

    目录 简介 队列的实现 队列的数组实现 队列的动态数组实现 队列的链表实现 队列的时间复杂度 简介 队列Queue是一个非常常见的数据结构,所谓队列就是先进先出的序列结构. 想象一下我们日常的排队买票 ...

  3. BUAA2020软工作业(四)——结对项目

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 进一步提高自己的编码能力,工程能力,团队协作能力 这个作业在哪 ...

  4. Spring Cloud Gateway Route Predicate Factory 的使用

    Spring Cloud Gateway的使用 一.需求 二.基本组成 1.简介 2.核型概念 1.Route 路由 2.Predicate 谓语.断言 3.Filter 过滤器 3.工作原理 三.网 ...

  5. dice_game攻防世界进阶区

    dice_game XCTF 4th-QCTF-2018 前言,不得不说,虽然是个简单题但是还是要记录一下,来让自己记住这些东西. 考察的知识点是: 1.cdll_loadlibrary加载对应库使得 ...

  6. 2021.8.17考试总结[NOIP42]

    $\huge{取模不能比大小!}$ $\huge{取模不能比大小!}$ $\huge{取模不能比大小!}$ 有了打地鼠的前车之鉴,我深信树规板子是可以出现在联赛题里的. 所以T1十分钟码完直接溜了,后 ...

  7. 全志Linux Tina编译demoOmxVdec错误

    测试裸流 Making install in demoOmxVdec make[6]: Entering directory '/home/liuxueneng/WorkCode/Homlet-Tin ...

  8. C#笔记1__命名空间 / 常量 / object / is、as、...?... :...

    命名空间:namespace Test1{ ... } 引用命名空间:using System; using 别名=命名空间 常量:const double PI=3.14; using System ...

  9. newusers 拷贝服务器A上的用户,批量添加到其它服务器

    服务器B 需要添加多个用户,要求与服务器A 的用户列表一致 1.拷贝服务器A 上的 /etc/passwd 中用户信息,用user1-10为例 #grep ^user /etc/passwd > ...

  10. SimpleNVR流媒体服务系统录像功能解析

    录像的回放与观看是许多人在使用视频监控时必不可少的需求.人不可能每时每刻都观看视频,而录像能对摄像机的视频信息进行存储,方便用户的后期回放查看,因此,SimpleNVR的录像功能应运而生.       ...