【持续更新】【专题】寒假后DP2 + 状压DP1

取数家族

取数1

\(f_{i,0/1}\) 表示取到了第 \(i\) 位,这位取/不取。

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=2e5+10;
int a[N],s[N],f[N][2];
int n;
void MAIN(){
	cin>>n;
	For(i,1,n){
		cin>>a[i];
	}
	For(i,1,n){
		f[i][0]=max(f[i-1][0],f[i-1][1]);
		f[i][1]=f[i-1][0]+a[i];
	}
	cout<<max(f[n][0],f[n][1])<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

取数2

只有取或不取两种情况,直接dp即可。

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=1e6+10;
#define int ll
int a[N],s[N],f[N];
int n;
void MAIN(){
	cin>>n;
	For(i,1,n){
		cin>>a[i];
	}
	f[1]=0,f[2]=a[1]+a[2];
	For(i,3,n){
		f[i]=max(f[i-1],f[i-3]+a[i]+a[i-1]);
	}
	cout<<f[n]<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

取数3

直接dp即可。

就比取数1多了一句话。

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=1e6+10;
ll a[N],s[N],f[N][2];
int n;
void MAIN(){
	cin>>n;
	For(i,1,n){
		cin>>a[i];
	}
	For(i,1,n){
		f[i][0]=max(f[i-1][0],f[i-1][1]);
		f[i][1]=f[i-1][0]+a[i];
		if(i>1)f[i][1]=max(f[i][1],f[i-2][0]+a[i]+a[i-1]);
	}
	cout<<max(f[n][0],f[n][1])<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

取数4「ABC162F」

记现在在第 \(i\) 位。

\(i\equiv 1\left(mod\space2\right)\) 时,将这个序列分为 \(\frac{i}{2}\) 段,每段 \(2\) 个数,且这些数不相邻,则需要每一段都选出 1 个数。

考虑此位选或不选。

  • 若选了第 \(i\) 个数,则第 \(i−1\) 个数就必须不选,答案为 \(f_{i-2}+a_{i}\)
  • 若不选第 \(i\) 个数,则第 \(i−1\) 个数就必须选,以此类推 必须选 \(a_{1},a_{3},a_{5}, \ ... ,a_{i-1}\),所以答案为 \(s_{i-1}\)

\(i\equiv 0\left(mod\space2\right)\) 时,则在这 \(i\) 个数中选择 \(\frac{i-1}{2}\) 个数。

  • 若选第 \(i\) 个数,同上。
  • 若不选,即在前 \(i-1\) 位选择 \(\frac{i-1}{2}\) 个数,即 \(f_{i-1}\)
#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=2e5+10;
#define int ll
int a[N],s[N],f[N];
int n;
void MAIN(){
	cin>>n;
	For(i,1,n){
		cin>>a[i];
		if(i==1) s[1]=a[1];
		else if(i&1) s[i]=s[i-2]+a[i];
	}
	For(i,2,n){
		if(i&1){
			f[i]=max(f[i-2]+a[i],f[i-1]);
		}
		else{
			f[i]=max(f[i-2]+a[i],s[i-1]);
		}
	}
	cout<<f[n]<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

泰迪熊

直接枚举4种泰迪熊的个数即可。

思路很简单,实现很麻烦/ll。

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=1e6;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=40;
int a1,a2,b1,b2;
int ch[]={0,1,1,2,2},num[]={0,1,2,1,2};
mint f[N][N][N][N][5][5];
void MAIN(){
	cin>>a1>>a2>>b1>>b2;
	f[0][0][0][0][0][0]=1;
	For(i1,0,a1)For(i2,0,a2)For(j1,0,b1)For(j2,0,b2)For(x,0,4)For(y,0,4){
		int d=f[i1][i2][j1][j2][x][y].x;
		if(d==0) continue;
		bool isa=ch[x]==1&&ch[y]==1;
		bool isb=ch[x]==2&&ch[y]==2;
		bool is1=num[x]==1&&num[y]==1;
		bool is2=num[x]==2&&num[y]==2;
		if(!isa&&!is1&&i1<a1) f[i1+1][i2][j1][j2][y][1]+=d;
		if(!isa&&!is2&&i2<a2) f[i1][i2+1][j1][j2][y][2]+=d;
		if(!isb&&!is1&&j1<b1) f[i1][i2][j1+1][j2][y][3]+=d;
		if(!isb&&!is2&&j2<b2) f[i1][i2][j1][j2+1][y][4]+=d;
	}
	mint ans=0;
	For(i,0,4)For(j,0,4) ans+=f[a1][a2][b1][b2][i][j];
	cout<<ans.x<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}

不喜欢非整数

先枚举选数个数 \(p\)

\(f_{i,j,k}\) 表示前 \(i\) 个数选 \(j\) 个数余数为 \(k\) 的情况数。

转移方程:

\[f_{i+1,j,k}=f_{i+1,j,k}+f_{i,j,k}\\ f_{i+1,j+1,(k+a_{i})mod\space k}=f_{i+1,j+1,(k+a_{i})mod\space k}+f_{i,j,k} \]

刷表做就行了。

#include <bits/stdc++.h>
using namespace std;

#define For(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<=(y);++i)
#define foR(i,x,y,...) for(int i=(x),##__VA_ARGS__;i>=(y);--i)
#define Rep(i,x,y,...) for(int i=(x),##__VA_ARGS__;i<(y);++i)
#define endl '\n'
#define debug(...)
#define debug1(a,i,...) cout<<i<<" "<<a[i]<<endl;
typedef long long ll;
#define fi first
#define se second
#define PII pair<int,int>
#define me(s,x) memset(s,x,sizeof s)
#define pb emplace_back

template<typename T=int>T read(){T x;cin>>x;return x;}
const int mod=998244353;
struct mint{
	int x;mint(int x=0):x(x<0?x+mod:x<mod?x:x-mod){}
	mint(ll y){y%=mod,x=y<0?y+mod:y;}
	mint& operator += (const mint &y){x=x+y.x<mod?x+y.x:x+y.x-mod;return *this;}
	mint& operator -= (const mint &y){x=x<y.x?x-y.x+mod:x-y.x;return *this;}
	mint& operator *= (const mint &y){x=1ll*x*y.x%mod;return *this;}
	friend mint operator + (mint x,const mint &y){return x+y;}
	friend mint operator - (mint x,const mint &y){return x-y;}
	friend mint operator * (mint x,const mint &y){return x*y;}
};mint Pow(mint x,ll y=mod-2){mint z(1);for(;y;y>>=1,x*=x)if(y&1)z*=x;return z;}
const int N=105;
int n;
mint f[N][N][N];
mint ans;
int a[N];
void MAIN(){
	cin>>n;
	For(i,1,n) cin>>a[i];
	For(p,1,n){
		me(f,0);
		f[1][0][0]=1;
		For(i,1,n)For(j,0,min(i,p))Rep(k,0,p){
			f[i+1][j][k]+=f[i][j][k];
			if(j!=p) f[i+1][j+1][(k+a[i])%p]+=f[i][j][k];
		}
		ans+=f[n+1][p][0];
	}
	cout<<ans.x<<endl;
}signed main(){
	int t=1;while(t--){
		MAIN();
	}
	return 0;
}
posted @ 2025-05-04 16:01  cruisexsy2011  阅读(9)  评论(0)    收藏  举报