Atcoder Educational DP Contest

A

每个点可以转移到后面的两个点,直接做复杂度 \(O(n)\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,h[N],dp[N]; 
void Mian(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>h[i];
	for(int i=1;i<=n;++i) dp[i]=INF;
	dp[1]=0;
	for(int i=1;i<=n;++i){
		chkmin(dp[i+1],dp[i]+llabs(h[i+1]-h[i]));
		chkmin(dp[i+2],dp[i]+llabs(h[i+2]-h[i]));
	}
	cout<<dp[n];
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

B

每个点可以转移到后面的 \(k\) 个点,直接做复杂度 \(O(nk)\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,k,h[N],dp[N]; 
void Mian(){
	cin>>n>>k;
	for(int i=1;i<=n;++i) cin>>h[i];
	for(int i=1;i<=n;++i) dp[i]=INF;
	dp[1]=0;
	for(int i=1;i<=n;++i){
		for(int j=i+1;j<=i+k && j<=n;++j)
			chkmin(dp[j],dp[i]+llabs(h[i]-h[j]));
	}
	cout<<dp[n];
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

C

开一维存储当前点选取的活动即可,时间复杂度 \(O(n)\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,a[N][3],dp[N][3]; 
void Mian(){
	cin>>n;
	for(int i=1;i<=n;++i) 
		for(int j=0;j<3;++j) cin>>a[i][j];
	for(int i=1;i<=n;++i) dp[i][0]=dp[i][1]=dp[i][2]=-INF;
	for(int i=1;i<=n;++i){
		for(int p=0;p<3;++p) for(int q=0;q<3;++q) if(p^q){
			chkmax(dp[i][p],dp[i-1][q]+a[i][p]);
		}
	}
	cout<<max(dp[n][0],max(dp[n][1],dp[n][2]));
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

D

背包 dp 板子题,直接做 \(O(nW)\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,m,w[N],v[N];
int dp[N],ans; 
void Mian(){
	cin>>n>>m;
	for(int i=1;i<=n;++i) cin>>w[i]>>v[i];
	for(int i=1;i<=n;++i)
		for(int j=m;j>=w[i];--j) 
			chkmax(dp[j],dp[j-w[i]]+v[i]);
	for(int i=0;i<=m;++i) chkmax(ans,dp[i]);
	cout<<ans; 
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

E

交换 dp 数组所存储的价值维度和重量维度即可,复杂度 \(O(n^2V)\)

很不错的小巧思。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,m,w[N],v[N],sum;
int dp[N],ans; 
void Mian(){
	cin>>n>>m;
	for(int i=1;i<=n;++i) cin>>w[i]>>v[i],sum+=v[i];
	for(int i=1;i<=sum;++i) dp[i]=INF;
	for(int i=1;i<=n;++i)
		for(int j=sum;j>=v[i];--j) 
			chkmin(dp[j],dp[j-v[i]]+w[i]);
	for(int i=sum;i>=0;--i) if(dp[i]<=m) return cout<<i,void();
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

F

LCS 板子。
输出字符序列的过程可以考虑逆着 dp 顺序来推。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=3000+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,m,dp[N][N];
string s,t; 
char ans[N];
void Mian(){
	cin>>s>>t;
	n=s.size(); s=" "+s;
	m=t.size(); t=" "+t;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			if(s[i]==t[j]) chkmax(dp[i][j],dp[i-1][j-1]+1);
			chkmax(dp[i][j],dp[i-1][j]);
			chkmax(dp[i][j],dp[i][j-1]);
		}
	}
	int i=n,j=m;
	while(dp[i][j]>0){
		if(s[i]==t[j]){
			ans[dp[i][j]]=s[i];
			--i; --j;
		}else{
			if(dp[i][j]==dp[i-1][j]) --i;
			else --j;
		}
	}
	for(int i=1;i<=dp[n][m];++i) cout<<ans[i];
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

G

拓扑排序即可。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=998244353,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,m,d[N],dp[N],ans;
vector<int> G[N];
queue<int> q;
void Mian(){
	cin>>n>>m;
	for(int i=1;i<=m;++i){
		int x,y; cin>>x>>y;
		G[x].push_back(y);
		++d[y];
	}
	for(int i=1;i<=n;++i) if(!d[i]) q.push(i);
	while(!q.empty()){
		int u=q.front(); q.pop();
		for(auto v:G[u]){
			--d[v];
			chkmax(dp[v],dp[u]+1);
			if(!d[v]) q.push(v);
		}
	}
	for(int i=1;i<=n;++i) chkmax(ans,dp[i]);
	cout<<ans;
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

H

为了简化代码,初始可以把 \(dp_{0,1}\) 赋为 \(1\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1000+9,M=(1<<23)+9;
const int MOD=1e9+7,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,m,dp[N][N];
char s[N][N]; 
void Mian(){
	cin>>n>>m;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j) cin>>s[i][j];
	dp[0][1]=1;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(s[i][j]=='.') dp[i][j]=(dp[i-1][j]+dp[i][j-1])%MOD;
	cout<<dp[n][m]; 
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

I

状态里记录正反的差值,滚动数组优化一下空间。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=3000+9,M=(1<<23)+9;
const int MOD=1e9+7,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n;
double p[N],dp[2][N*2],ans; 
void Mian(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>p[i];
	dp[0][n]=1;
	for(int i=1;i<=n;++i){
		int pos=(i&1);
		for(int j=0;j<=n*2;++j) dp[pos][j]=0;
		for(int j=0;j<=n*2;++j){
			if(j) dp[pos][j]+=dp[pos^1][j-1]*p[i];
			if(j<n*2) dp[pos][j]+=dp[pos^1][j+1]*(1-p[i]);
		}
	}
	for(int i=n;i<=2*n;++i) ans+=dp[n&1][i];
	printf("%.15lf",ans); 
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

J

简单的期望 dp。
\(dp_{i,j,k}\) 分别为寿司数为 \(1,2,3\) 的盘子,观察柿子可以得出转移顺序应该为 k,j,i,道理是 k 维度不含 k+1 项的转移,j+1 项在 k-1 维度,i+1 项在 j-1 维度。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=300+9,M=(1<<23)+9;
const int MOD=1e9+7,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,a[4];
double dp[N][N][N]; 
void Mian(){
	cin>>n;
	for(int i=1;i<=n;++i){
		int x; cin>>x;
		a[x]++;
	} 
	for(int k=0;k<=n;++k){
		for(int j=0;j<=n;++j){
			for(int i=0;i<=n;++i){
				if(i) dp[i][j][k]+=i*dp[i-1][j][k];
				if(j) dp[i][j][k]+=j*dp[i+1][j-1][k];
				if(k) dp[i][j][k]+=k*dp[i][j+1][k-1];
				if(i+j+k) (dp[i][j][k]+=n)/=(i+j+k);
			}
		}
	} 
	printf("%.15lf",dp[a[1]][a[2]][a[3]]);
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

K

一个状态是必胜态当且仅当其存在必败的后继状态。
一个节点是必败态当且仅当其后继状态全是必胜态。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=1e5+9,M=(1<<23)+9;
const int MOD=1e9+7,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,k,a[N],dp[N]; 
void Mian(){
	cin>>n>>k;
	for(int i=1;i<=n;++i) cin>>a[i];
	dp[0]=0;
	for(int i=0;i<=k;++i)
		for(int j=1;j<=n;++j)
			if(i+a[j]<=k) dp[i+a[j]]|=(!dp[i]);
	if(!dp[k]) puts("Second");
	else puts("First");
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}

L

直接区间 dp,状态 \(O(n^2)\) 转移 \(O(1)\),总复杂度 \(O(n^2)\)

AC Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define INF (int)(1e9)
#define fir first
#define sec second

const int N=3000+9,M=(1<<23)+9;
const int MOD=1e9+7,base=251;
inline void chkmax(int &x,int y){x=x<y?y:x;}
inline void chkmin(int &x,int y){x=x<y?x:y;}
inline int lowbit(int x){return x&(-x);}
int qpow(int a,int b,int p){
    int ret=1;
    while(b){
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}

int n,a[N];
int dp[N][N]; 
void Mian(){
	cin>>n;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int len=1;len<=n;++len){
		int gt=((n-len)&1)^1;
		for(int i=1,j;i+len-1<=n;++i){
			j=i+len-1;
			if(gt) dp[i][j]=max(dp[i+1][j]+a[i],dp[i][j-1]+a[j]);
			else dp[i][j]=min(dp[i+1][j]-a[i],dp[i][j-1]-a[j]);
		}
	}
	cout<<dp[1][n];
}
void Mianclr(){
	
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);

    int T=1; //cin>>T;
    while(T--){
    	Mian();
		Mianclr(); 
	}
}
posted @ 2026-01-25 22:26  Mi2uk1  阅读(2)  评论(0)    收藏  举报