题目传送门(内部题2)


输入格式

每个测试点有多组测试数据。
对于每组数据,有一行共三个整数$N$,$D$,$M$含义如题。
输入结束标识为$“0 0 0”$ (不含引号)。


输出格式

对于每组数据,输出一行共一个整数,表示方案数对$998244353$取膜后的结果。


样例

样例输入:

5 2 5
3 3 3
5 4 5
4 1 2
1 5 1
1250 50 50
0 0 0

样例输出:

4
7
52
0
0505279299


数据范围与提示

$T \leqslant 10$

对于$30\%$的数据:

$N \leqslant 20$

$D \leqslant 20$

$M \leqslant 10$

对于$100\%$的数据:

$N \leqslant 2000$

$D \leqslant {10}^{12}$

$M \leqslant 2000$


题解

$30\%$算法:

要注意每天给她的饼干数要少于M,没有等于。

看到这道题,首先应该想到DP,定义dp[i][j]表示到第i天,还剩j个饼干的方案数。

那么很轻易的就可以列出状态转移方程:

$dp[i][j]= \sum \limits_{k=0}^{ \min(M-1,N-j)} dp[i-1][j+K]$

时间复杂度:$O(N \times D \times M)$。

空间复杂度:$D \times N$。

期望得分:$30$分。

实际得分:$30$分。

$30\%$算法(进阶):

上面的算法显然空间不能接受,那么我们应该怎么优化呢?

发现$D$很大,但是我们又发现真正会给她饼干之多$N$天。

那么我们就相当与将天数压缩到$N$天,显然在空间上就可以接受了。

定义$dp[i][j]$表示真的给她饼干的天数为$i$,一共给出了$j$块饼干的方案数。

那么就又可以列出状态转移方程了:

$dp[i][j]= \sum \limits_{k=\max(j-M+1,0)}^{j-1} dp[i-1][K]$

答案即为:$ans= \sum \limits_{i=1}^{N} dp[i][N] \times C_D^i$。

至于如何计算$C_D^i$:

显然杨辉三角打表无论是时间上还是空间上都不能接受,$Lucas$定理时间上也不能够接受,所以这两种常用的方式显然都行不通,所以我们考虑化简式子:

$C_D^i = \frac{D!}{i! \times (D-i)!} = \frac {D-i+1 \times D-i+2 \times ... \times D-1 \times D}{1 \times 2 \times ... \times i-1 \times i}$

虽然$D$很大,但是$i \leqslant N$所以我们只需要计算很小的一段区间即可,无论是时间上还是空间上都的到了解决。

时间复杂度:$O(N^2 \times M)$。

空间复杂度:$N^2$。

期望得分:$30$分。

$100\%$算法:

发现上面$30\%$(进阶)的算法中,枚举K的循环可以使用前缀和优化实现$O(1)$转移。

时间复杂度:$O(N^2)$。

空间复杂度:$N^2$。

期望得分:100分。


代码时刻

$30\%$代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long d;
long long dp[2010][2010];//数组不要过大
int main()
{
while(1)
{
scanf("%d%lld%d",&n,&d,&m);
if(!n&&!m&&!d)break;
memset(dp,0,sizeof(dp));
dp[0][n]=1;
for(int i=1;i<=d;i++)
for(int j=0;j<=n;j++)
for(int k=0;k<m&&j+k<=n;k++)
dp[i][j]=(dp[i][j]+dp[i-1][j+k])%998244353;//状态转移
printf("%lld\n",dp[d][0]);
}
return 0;
}

$30\%$算法(进阶):

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long d;
long long dp[2010][2010];
long long ans;
long long p[2010],jc[2010],qsm[2010],c[2010];
long long qpow(long long x,long long y)
{
long long ans=1;
while(y)
{
if(y&1)ans=(ans*x)%998244353;
y>>=1;
x=(x*x)%998244353;
}
return ans;
}
void pre_work_wzc()//预处理
{
jc[0]=1;
for(int i=1;i<=2000;i++)
jc[i]=jc[i-1]*i%998244353;
for(int i=0;i<=2000;i++)
qsm[i]=qpow(jc[i],998244351)%998244353;
}
void pre_work()//还是预处理
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
ans=0;
p[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=(d-i+998244354)%998244353*p[i-1]%998244353;
c[i]=p[i]*qsm[i]%998244353;
}
}
int main()
{
pre_work_wzc();
while(1)
{
scanf("%d%lld%d",&n,&d,&m);
if(!n&&!m&&!d)break;
pre_work();
for(int i=1;i<=min((long long)n,d);i++)
for(int j=i;j<=n;j++)
for(int k=max(j-m+1,0);k<j;k++)
dp[i][j]=(dp[i][j]+dp[i-1][k])%998244353;//状态转移
for(int i=1;i<=n;i++)
ans=(ans+dp[i][n]*c[i])%998244353;//统计答案
printf("%lld\n",ans);
}
return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long d;
long long dp[2010][2010];
long long flag[2010][2010];//前缀和数组
long long ans;
long long p[2010],jc[2010],qsm[2010],c[2010];
long long qpow(long long x,long long y)
{
long long ans=1;
while(y)
{
if(y&1)ans=(ans*x)%998244353;
y>>=1;
x=(x*x)%998244353;
}
return ans;
}
void pre_work_wzc()
{
jc[0]=1;
for(int i=1;i<=2000;i++)
jc[i]=jc[i-1]*i%998244353;
for(int i=0;i<=2000;i++)
qsm[i]=qpow(jc[i],998244351)%998244353;
}
void pre_work()
{
memset(dp,0,sizeof(dp));
ans=0;
p[0]=1;
for(int i=1;i<m;i++)
dp[1][i]=1;
for(int i=1;i<=n;i++)
{
p[i]=(d-i+998244354)%998244353*p[i-1]%998244353;
c[i]=p[i]*qsm[i]%998244353;
flag[1][i]=flag[1][i-1]+dp[1][i];
}
}
int main()
{
pre_work_wzc();
while(1)
{
scanf("%d%lld%d",&n,&d,&m);
if(!n&&!m&&!d)break;
pre_work();
for(int i=2;i<=min((long long)n,d);i++)
for(int j=i;j<=n;j++)
{
dp[i][j]=(flag[i-1][j-1]-flag[i-1][max(j-m,0)]+998244353)%998244353;
flag[i][j]=(flag[i][j-1]+dp[i][j])%998244353;
}
for(int i=1;i<=n;i++)
ans=(ans+dp[i][n]*c[i])%998244353;
cout<<ans<<endl;
}
return 0;
}

rp++

[CSP-S模拟测试]:那一天我们许下约定(DP+组合数学)的更多相关文章

  1. [CSP-S模拟测试]:停不下来的团长奥尔加(DP)

    题目传送门(内部题125) 输入格式 第一行一个整数$n$,含义同题中所述. 第二行$n$个整数,第$i$个数表示$p_i$,含义同题中所述. 输出格式 一行一个整数,表示答案对$1000000007 ...

  2. [CSP-S模拟测试]:小奇的仓库(warehouse)(树形DP)

    题目背景 小奇采的矿实在太多了,它准备在喵星系建个矿石仓库.令它无语的是,喵星系的货运飞船引擎还停留在上元时代! 题目描述 喵星系有$n$个星球,星球以及星球间的航线形成一棵树.从星球$a$到星球$b ...

  3. [CSP-S模拟测试]:卡常题/b(基环树+DP)

    题目描述 $ρ$有一个二分连通无向图,$X$方点.$Y$方点均为$n$个(编号为$1\sim n$).这个二分图比较特殊,每一个$Y$方点的度为$2$,一条黑色边,一条白色边.所有黑色边权值均为$a$ ...

  4. [NOIP模拟测试9]题(Problem) 题解 (组合数全家桶+dp)

    达哥送分给我我都不要,感觉自己挺牛批. $type=0:$ 跟visit那题类似,枚举横向移动的步数直接推公式: $ans=\sum C_n^i \times C_i^{\frac{i}{2}} \t ...

  5. NOIP模拟测试6「那一天我们许下约定(背包dp)·那一天她离我而去」

    那一天我们许下约定 内部题,题干不粘了. $30分算法$ 首先看数据范围,可以写出来一个普通dp #include<bits/stdc++.h> #define ll int #defin ...

  6. 【模拟7.19】那一天我们许下约定(组合数学,DP)

    看了题目名字深切怀疑出题人是不是失恋了,然后出题折磨我们.然后这题就愉快的打了个暴力,最后莫名其妙wa20,伤心..... 其实这题正解不是很难想,如果说把暴力的DP搞出来,正解也差不到哪去了, 我们 ...

  7. Android单元测试与模拟测试详解

    测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabri ...

  8. [开源]微信在线信息模拟测试工具(基于Senparc.Weixin.MP开发)

    目前为止似乎还没有看到过Web版的普通消息测试工具(除了官方针对高级接口的),现有的一些桌面版的几个测试工具也都是使用XML直接请求,非常不友好,我们来尝试做一个“面向对象”操作的测试工具. 测试工具 ...

  9. 安装nginx python uwsgi环境 以及模拟测试

    uwsgi帮助文档: http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html http://uwsgi-docs.re ...

随机推荐

  1. # 风险定性(Qualitative)分析

    1. 从一个给教师打分的设计表说起 我们参加一个培训课程,一般在培训结束之后,培训机构一般都会分发一份培训师培训效果反馈表,用于评价其讲师的培训能力的强弱. 如果是一家没有什么经验的培训机构设计的反馈 ...

  2. 经典算法,yuv与rgb互转,查表法,让你的软件飞起来

    代码的运算速度取决于以下几个方面 1. 算法本身的复杂度,比如MPEG比JPEG复杂,JPEG比BMP图片的编码复杂. 2. CPU自身的速度和设计架构 3. CPU的总线带宽 4. 您自己代码的写法 ...

  3. MFC + XToolKit的使用 ( 亲自实践 )

    1. 变量声明: 在Dlg.h    的public下 CXTPButton m_Button2; 2. 变量交换并设置按钮风格: Dlg.cpp下 void CXT_VS2010Dlg::DoDat ...

  4. 帝国cms 修改分页样式

    帝国cms 修改分页样式(路径) /e/class/t_functions.php

  5. ztree树id、pid转成children格式的(待整理完整)

    山铝菜单 因为菜单选用了bootstrap treeview ,而格式需要是children类似的格式 var nodes = [ {name: "父节点1", children: ...

  6. Python中GUI库PyQt5的安装和配置

    在使用Tkinter开发GUI程序时,发现相关文档比较少,开发起来太累.经过综合比较,决定使用PyQt这个库.下面是简单的安装步骤. 1.安装 PyQt5 : pip install PyQt5 -i ...

  7. MySQL表内更新时,自动记录时间

    1.创建表: create table test_time(id int primary key not null,status  varchar(24),create_time datetime d ...

  8. web录音——上传录音文件

    捕获麦克风 一.  前言    公司项目需要实现web录音,刚刚好接手此功能,由于之前未接触过,在网上找了些资料做对比 )   https://www.cnblogs.com/starcrm/p/51 ...

  9. 2019-11-29-解决从旧格式的-csproj-迁移到新格式的-csproj-格式-AssemblyInfo-文件值重复问题...

    title author date CreateTime categories 解决从旧格式的 csproj 迁移到新格式的 csproj 格式 AssemblyInfo 文件值重复问题 lindex ...

  10. Oracle 触发器学习笔记一

    触发器名:触发器对象的名称.由于触发器是数据库自动执行的,因此该名称只是一个名称,没有实质的用途.触发时间:指明触发器何时执行,该值可取:before:表示在数据库动作之前触发器执行;after:表示 ...