Tricks

1.对于一道题如果思路不清晰,不妨把框架先打出来,再顺着框架解决问题
2.思路不清晰或者容易忘记推导过程,可以在注释里写一写思路和一些看出来的结论
3.该拼部分分拼部分分,即使过了拍也最好写一下数据点分治,也可以根据部分分剪剪枝,免得正解挂了部分分都拿不到。
4.空间大小一定要算清楚,既要避免用 STL 炸空间,又一定一定要开足。
5.要特别注意明显过小的数据范围,那很可能是突破口。
6.没思路时打表找找规律。有特殊性质可以手动模拟一下一些小的特殊情况
7.有重叠子问题的时候不妨考虑一下DP
8.有时候DP问题可以用组合计数和找规律来优化,反之也是可以的
9.数据范围不利于dp开许多维数的时候,可以状压,压缩用得到的状态
10.计算mid的时候,为了防止(l+r)/2爆掉类型,可以采用l+(r-l)/2的形式
11.二分时要注意区间是左闭右开还是左右都闭
12.modint解决忘记取模或者式子取模太复杂的问题

// modint from Rainbow_qwq
#define mod 998244353
struct modint{
	int x;
	modint(int o=0){x=o;}
	modint &operator = (int o){return x=o,*this;}
	modint &operator +=(modint o){return x=x+o.x>=mod?x+o.x-mod:x+o.x,*this;}
	modint &operator -=(modint o){return x=x-o.x<0?x-o.x+mod:x-o.x,*this;}
	modint &operator *=(modint o){return x=1ll*x*o.x%mod,*this;}
	modint &operator ^=(int b){
		modint a=*this,c=1;
		for(;b;b>>=1,a*=a)if(b&1)c*=a;
		return x=c.x,*this;
	}
	modint &operator /=(modint o){return *this *=o^=mod-2;}
	friend modint operator +(modint a,modint b){return a+=b;}
	friend modint operator -(modint a,modint b){return a-=b;}
	friend modint operator *(modint a,modint b){return a*=b;}
	friend modint operator /(modint a,modint b){return a/=b;}
	friend modint operator ^(modint a,int b){return a^=b;}
	friend bool operator ==(modint a,int b){return a.x==b;}
	friend bool operator !=(modint a,int b){return a.x!=b;}
	bool operator ! () {return !x;}
	modint operator - () {return x?mod-x:0;}
	bool operator <(const modint&b)const{return x<b.x;}
};
inline modint qpow(modint x,int y){return x^y;}

vector<modint> fac,ifac,iv;
inline void initC(int n)
{
	if(iv.empty())fac=ifac=iv=vector<modint>(2,1);
	int m=iv.size(); ++n;
	if(m>=n)return;
	iv.resize(n),fac.resize(n),ifac.resize(n);
	For(i,m,n-1){
		iv[i]=iv[mod%i]*(mod-mod/i);
		fac[i]=fac[i-1]*i,ifac[i]=ifac[i-1]*iv[i];
	}
}
inline modint C(int n,int m){
	if(m<0||n<m)return 0;
	return initC(n),fac[n]*ifac[m]*ifac[n-m];
}
inline modint sign(int n){return (n&1)?(mod-1):(1);}


13.DP

常见的DP问题形式:

        1.求某种选取方案可得的最大值、最小值
        2.求某要求下的方案数
        3.累计递推结果
        4.数学公式、结论、期望、概率推到
        5.由多部分可以组成的问题,多部分合成可得
        6.背包问题及其变形

常见DP状态总结:

        1.前i行的最大/最小值
        2.第i行第j列之前最大/最小值
        3.可以新开一个数组记录位置之间的关系,便于转移,或者优化转移 CF1183H
        4.0/1表示取或不取 或者变换的方式
        5.0/1/2/3...表示方向、特殊转移状态、分类讨论的情况
        6.i,j...表示位置、坐标
        7.选了j个/用了j个  物品数量... 时间...
        8.花费、代价为j(如背包、调度类问题)
        9.凑数时符合要求的子数,如符合要求的i+j=x,转移时可以将x拆分为i,j两部分合成转移
        10.[i,j]区间的极值
        11.区间DP的区间1个端点和1个断点,区间dp的精髓为区间长度的枚举
        12.表示长度/高度/距离为i
        13.一棵树中到节点u可达最大/小值
        14.以该节点为根的子树的状态
        15.表示从节点i到节点j
        16.应题目要求可设计的某个特殊值的多少
        17.节点的颜色or其他状态

关于期望DP

        某一变量的概率乘以这一变量值,再求和,就是数学期望
        期望$DP$,就是根据概率分析,递推求出每个状态的期望的算法

期望DP常见的状态设法及其转移:

      1、设成dp[i]表示已经完成i个,要达到目标状态的期望。也就是由i状态变成目标状态的期望。
      对于这种方法,转移的时候要选择刷表法倒序枚举。(根据这个状态本身就可以理解)
      2、设成dp[i]表示已经完成i个的期望。
      对于这种方法,转移的时候要选择填表法正序枚举。
      对于以上两种方法,很多时候可以互换。但是有些时候不能互换。需要经过具体情况灵活判断。
      3、设成dp[i][j]表示i种物品选择了j个的期望。
      4、设成dp[i][j]表示有i个第一种物品,j个第二种物品的期望。
      对于以上两种方法,就是二维的状态转移。

切DP题的步骤总结:

      1.确定状态
      2.根据数据范围要求进行优化、简化状态
      3.根据无后效性原则设计状态转移方程
      4.由方程的需要对dp数组和需用的变量、数组进行预处理
      5.由题目要求,选择、筛选需要的答案

番茄&zak语录之dp:

      1.对比自己与别人的思路
      2.积累是创造的一大来源
      3.提高熟练度
      4.增加想法间的联系
      5.dp的关键在于把问题拆分成若干子问题
      6.启发式的题目往往会帮助拥有思维
      7.掌握套路

Tips:有时候遇到一个DP题,感觉状态复杂,不妨分成多个DP问题

14.当一个问题可以从先前的某些子问题以相同的形式转化过来,不妨用矩阵的方式建模,用矩阵加速解决问题

posted @   Diamondan  阅读(68)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示