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();
}
}

浙公网安备 33010602011771号