计数dp
错位排列计数 (组合意义dp)
题目
给定长度为
题解
设
- 直接与前面的数交换,有
种方案 - 放在前面某个数的位置上,那么相当于给原来
个数做了错排,有 中方案
所以
这个递推式可以求出其通项,但这不是本博客讨论的范围,读者感兴趣的自行了解即可
NOIP 四校联测 Day1 T2 (组合意义dp)
题目
给定两个排列
题解
首先我们考虑没有字典序的限制要怎么做,设
也就是我们当前的
考虑正解
一眼丁真,类似数位dp,应该是要进行一个差分的,也就是
于是我们考虑从前到后枚举每一位,以
因此前
考虑
设前
而
然后把所有
NOIP 四校联测 Day2 构造数组 (辨认无意义的状压dp+组合意义dp)
题目
你现在有一个长度为
- 选出两个不同的下标
,并将 和 同时增加 。
两种方案被称之为不同的,当且仅当存在一个
题解
这道题感觉出的挺好的,部分分给的挺多的,正解是不太好想的,考场上花了好长时间想,最后也没调出来
首先我们可以将这个问题转化成,我现在有
一种朴素的状压dp做法是,考虑设
然而我们发现我们其实并不关心每个桶放数的情况,我们只关心放了
更进一步,我们发现知道了个数为
时间复杂度
容斥原理套路于DP
容斥原理在dp中有如下的经典应用:
一般容斥原理直接暴力做的复杂度是
P5664 [CSP-S2019] Emiya 家今天的饭 (容斥原理套路1)
题解
首先,如果直接考虑本题合法的方案数,我们发现题目中的限制有些过于多了,正难则反,考虑容斥
所以我们可以钦定一定有某一种食材超过了限制,那么答案就是总的方案数减去不合法的方案数。设
不合法的方案数就是
设
于是
就是我们的总方案数
综合来看,我们目前的时间复杂度是
这就是这道题最经典的地方了,我们发现对于
于是时间复杂度就降为了
P1450 [HAOI2008] 硬币购物 (容斥原理套路1)
题目
共有
某人去商店买东西,去了
题解
与上一道题同理,直接利用分组背包计算合法的方案数肯定是T飞了的,所以同样考虑容斥
我们分别钦定有
BZOJ3622 已经没什么好害怕的了 (容斥原理套路3)
题目
给定
题解
无序的序列过于丑陋,所以我们先要对两个序列先进行一个排序
设
同样与上一题类似,设
我们想要的就是
我们现在对
时间复杂度
HDU 4336 Card Collector (容斥原理套路4 min-max容斥)
题目
有
题解
记
又因为单位时间内
所以,对于本题,
我们套用
时间复杂度
ARC101E Ribbons on Tree (容斥原理套路2)
题目
给定一个
题解
直接计算是
所以考虑容斥,设
其中
设
设
对于
对于
时间复杂度
BZOJ 4767 两双手 (容斥原理套路2)
题目
棋盘上
求棋子从
题解
因为两个向量不共线,由平面向量基本定理,加之旗子只有两种走法,我们可以找到对于一个变换后坐标为
接着我们考虑容斥原理的套路
时间复杂度是
ZR2022 NOIP十连测 Day5 T3 (数位dp+容斥原理套路1)
题目
小K想知道你可不可以帮他验算。
小K有
小K已经用超级计算机计算出了精确值,所以你只需要算出答案乘上
题解
毒瘤题!
乍一看就很像一个数位dp,但这道题困难的地方在于如何求出每一个
然后难的就是这一部分,所以我把这题归到了计数dp中(尽管它看着更像是一个数位dp)
我们设
组合意义就是对大于
于是我们要求的答案就变成了
其中
这个东西显然是可以
这样我们的问题就转化为求
我们参考以往数位dp的经验,对上面那个式子进行转移,设
即从
转移而来
最后注意
时间复杂度
[SRM 697] ConnectedStates (prufer序列计数)
题目
有
题解
吐槽:真毒瘤
这是一个有标号无根树问题,所以我们可以考虑搞出它的
对于一个固定的
贡献就再乘上度数之积为
然后我们再算有多少种
因此我们最终所要求的东西就是
设
所以暴力转移的复杂度是
考虑使用多项式的幂公式,即
我们令
现在我们离化简只差
所以类比到整个式子就变成了
转移就是
那么这道题就可以
ZR2023 NOIP赛前20连测 Day1 T3 (组合意义转多项式优化dp)
[题意](【noip赛前20天冲刺集训 day1】迷路 - 题目 - Zhengrui Online Judge (zhengruioi.com))
题解
题目的意思可以简化成,从每个起点出发,根据是否碰到树可以记作
从第一步到第
考虑 dp ,设
于是这里开始上多项式了,我们设当前等价类的大小分别为
这样总时间复杂度即为
ZR2023 NOIP赛前20连测 Day6 T3 (插板法+底数较小组合数的处理方法)
题意
你当前想要做一个有关概率的问题。
具体的,有
当前你需要计算有多少概率使得变量的和小于等于为
当然你并不满足于此,你尝试将这
要求这个十进制数大小
你需要对
为了方便,你只需要输出满足条件的概率乘上
由于答案可能很大,你只需要输出答案在
对于所有测试点满足
题解
首先,你仔细想一下我们上面提到的常规数位dp做法,会发现它很困难,出题人的意思是可以用多项式做,挺抽象的
所以我们考虑另一种做法,我们将所有的
考虑如何求出
注意到一个位置的贡献最高是
然后由于
总时间复杂度即为
带注释代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
return x*f;
}
const int mod=998244353,M=1010,P=51;
int up[M],dw[M],fac[M],ifac[M];
int n,p,m,N;
inline int ksm(int a,int b)
{
int val=1;
while(b)
{
if(b&1) val=val*a%mod;
a=a*a%mod;
b>>=1;
}
return val;
}
inline void init(int n)
{
N=n;
dw[0]=1;
for(int i=1;i<M;++i) dw[i]=dw[i-1]*(n-i+1)%mod;
up[0]=1;
for(int i=1;i<M;++i) up[i]=up[i-1]*(n+i-1)%mod;
}
inline int Cd(int x)
{
if(x>N) return 0;
return dw[x]*ifac[x]%mod;
}
inline int Cu(int x)
{
return up[x]*ifac[x]%mod;
}
int ok[M],id[M],val[M],cnt[M];
int g[P][M];
int f[P][M][P];
signed main()
{
n=read();p=read();m=read();
fac[0]=1;
for(int i=1;i<M;++i) fac[i]=fac[i-1]*i%mod;
ifac[M-1]=ksm(fac[M-1],mod-2);
for(int i=M-2;i>=0;--i) ifac[i]=ifac[i+1]*(i+1)%mod;
int u=1,tot=0,L=0,R=-1;
for(int i=1;i<=n;++i)//找模p意义下的循环节,用来计算各个剩余类的大小
{
u%=p;
if(ok[u])
{
L=id[u];R=i-1;
break;
}
++cnt[u];
id[u]=++tot;
val[tot]=u;
ok[u]=1;
u*=10;u%=p;
}
if(R!=-1)
{
int k=(n-R)/(R-L+1);
for(int i=L;i<=R;++i) cnt[val[i]]+=k;
u=val[R]*10%p;
for(int i=R+k*(R-L+1)+1;i<=n;++i)
{
u%=p;
++cnt[u];
id[u]=++tot;
val[tot]=u;
ok[u]=1;
u*=10;u%=p;
}
}
for(int i=0;i<p;++i)
{
init(cnt[i]);
for(int j=0;j<=m;++j)
{
int res=0;
for(int k=0;;++k)
{
if(j<10*k) break;
if(k&1) res+=(mod-1)*Cd(k)%mod*Cu(j-10*k)%mod;
else res+=Cd(k)*Cu(j-10*k)%mod;
}
g[i][j]=res%mod;//第 i 个剩余类,给数位和贡献 j 的方案数
}
}
f[0][0][0]=1;//考虑到第 i 个剩余类 ,数位和为 j ,取模结果为 k 时的方案数
for(int i=0;i<p;++i)
for(int j=0;j<=m;++j)
for(int k=0;k<p;++k)
{
if(!f[i][j][k]) continue;
for(int d=0;d<=min(m-j,cnt[i]*9);++d)// 当前考虑贡献 d 到数位和
(f[i+1][j+d][(k+d*i)%p]+=f[i][j][k]*g[i][d])%=mod;
}
for(int i=1;i<=m;++i) (f[p][i][0]+=f[p][i-1][0])%=mod;
for(int i=0;i<=m;++i) cout<<f[p][i][0]<<' ';
return 0;
}
ZR2023 NOIP赛前20连测 Day7 T3 (强限制优先+调和级数)
题意
有
组与组之间是不可区分的, 每组的人也是无序的, 但人与人之间是可以区分的.
题解
由于大的组限制更强,所以我们贪心地考虑,排序之后根据组的大小从大到小考虑
设
第二个组合数下面有
由于
时间复杂度
ZR2023 NOIP赛前20连测 Day9 T3 (组合意义转多项式优化dp)
题意
假设存在
若序列
若序列
空串既是第一类括号序列又是第二类括号序列。
简单来说,第一类括号序列只允许匹配时左括号在左边,右括号在右边,而第二类括号序列允许相反顺序的括号匹配。你的任务是,给定正整数
由于答案可能很大,对 998244353 取模即可。
对于所有数据,
题解
设
第一个式子考虑容斥,总方案数
第二个式子同样考虑枚举切分点
接下来考虑使用 GF 技巧来快速计算上面的式子
我们设
第一个式子乘
第二个式子考虑一个括号序列可以由多个不可切分的括号序列组成,所以式子形如
然后这个东西的封闭形式是经典的
然后通过我们高超的初二数学技巧,我们解出来
然后这里题解给了一个很微妙的类似于求解常微分方程的做法,具体来说,设
对
分母有理化得
然后考虑第
得到
这样这道题就做完了,由于只用求
代码里懒得线性求逆元了,所以复杂度是
posted on 2023-10-27 18:07 star_road_xyz 阅读(62) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】