关于dp部分的思考

发布时间 2023-06-23 08:54:42作者: EnderWave

dp部分小结

背包

背包主要是模型的构建。

01背包

选与不选,且只能选一个。

for(int i=1;i<=n;i++){
    for(int j=mt;j>=w[i];j--)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}

完全背包

选与不选,可任意选。

for(int i=1;i<=n;i++){
    for(int j=w[i];j<=mt;j++)
        dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}

多重背包

选与不选,有数目限制。

  • 考虑二进制拆分,讲一个大小为n的物品拆成O(logn)个物品

分组背包

选与不选,每组只能选一个

区间

枚举区间断点

\( dp_{i,j}=max(dp_{i,k}+dp_{k+1,j}) \)

\( dp_{i,j}=max(dp_{i,k-1}+dp_{k+1,j}+c_k) \)

枚举区间最后一个点

数位

比较套路,只要确定好状态和限制就好了

ll dfs(int pos,int num,int lim,int d){
	if(!pos)return num==d;
	if(~dp[pos][num][lim][d])return dp[pos][num][lim][d];
	int ma=lim?bit[pos]:1;
	ll res=0;
	for(int i=0;i<=ma;i++){
		res+=dfs(pos-1,num+(i==1),lim&&i==ma,d);
	}
	return dp[pos][num][lim][d]=res;
}

状压

最好提前预处理合法状态

  • 枚举子集
for(int i=st;i;i=(i-1)&st)
  • 判断是否冲突
if((s1&s2)||(s1&(s2<<1))||((s1<<1)&s2))continue;

环形

树形

换根