Atcoder Educational DP Contest 题解

A - Frog 1/B - Frog 2

入门...

复制代码
 1 #include<cstdio>
 2 #define abs(a) ((a)>=0?(a):(-(a)))
 3 #define min(a,b) ((a)<(b)?(a):(b)) 
 4 #define maxn 100050
 5 using namespace std;
 6 int dp[maxn],a[maxn];
 7 int main(){
 8     int n,k=2;
 9     scanf("%d",&n);
10     for (int i=1;i<=n;i++)
11     scanf("%d",&a[i]),dp[i]=1e9;
12     dp[1]=0;
13     for (int i=2;i<=n;i++){
14         for (int j=1;j<=k;j++)
15         if (i-j>0) dp[i]=min(dp[i],dp[i-j]+abs(a[i-j]-a[i]));
16     }
17     printf("%d\n",dp[n]);
18     return 0;
19 }
A and B
复制代码

C - Vacation

dp[i][0/1/2] 表示到第 i 个 这一个选 0/1/2 转移就很显然了....

复制代码
 1 #include<cstdio>
 2 #define max(a,b) ((a)>(b)?(a):(b))
 3 #define maxn 100050
 4 using namespace std;
 5 int dp[maxn][3];
 6 int main(){
 7     int n;
 8     scanf("%d",&n);
 9     for (int i=1;i<=n;i++){
10         int a,b,c;
11         scanf("%d%d%d",&a,&b,&c);
12         dp[i][0]=max(dp[i-1][1],dp[i-1][2])+a;
13         dp[i][1]=max(dp[i-1][0],dp[i-1][2])+b;
14         dp[i][2]=max(dp[i-1][0],dp[i-1][1])+c;
15     }
16     printf("%d\n",max(max(dp[n][0],dp[n][1]),dp[n][2]));
17     return 0;
18 }
C
复制代码

D - Knapsack 1

裸背包

复制代码
 1 #include<cstdio>
 2 #define ll long long
 3 #define max(a,b) (a>b?a:b)
 4 #define maxn 100050
 5 using namespace std;
 6 ll dp[maxn];
 7 int main(){
 8     int n,W;
 9     scanf("%d%d",&n,&W);
10     for (int i=1;i<=n;i++){
11         int a,b;
12         scanf("%d%d",&a,&b); 
13         for (int j=W;j>=a;j--)
14         dp[j]=max(dp[j-a]+b,dp[j]);
15     }
16     ll ans=0;
17     for (int j=0;j<=W;j++)
18     if (dp[j]>ans) ans=dp[j];
19     printf("%lld\n",ans);
20     return 0;
21 }
D
复制代码

E - Knapsack 2

发现价值比较小,那么换一下 dp 的状态表示

dp[j] 表示价值为 j 的最小重量

答案就从大到小枚举 W 的即可。

复制代码
 1 #include<cstdio>
 2 #define ll long long
 3 #define max(a,b) (a>b?a:b)
 4 #define maxn 100050
 5 #define min(a,b) (a<b?a:b)
 6 using namespace std;
 7 ll dp[maxn];
 8 int main(){
 9     int n,W;
10     scanf("%d%d",&n,&W);
11     for (int j=1;j<=1e5;j++)
12     dp[j]=1e12;
13     for (int i=1;i<=n;i++){
14         int a,b;
15         scanf("%d%d",&a,&b); 
16         for (int j=1e5;j>=b;j--)
17         dp[j]=min(dp[j-b]+a,dp[j]);
18     }
19     for (int i=1e5;i>=0;i--)
20     if (dp[i]<=W) return printf("%d\n",i),0;
21     return 0;
22 }
23 /*
24 dp[i][j]表示前i个价值和为j的最小重量 
25 */
E
复制代码

 F - LCS

裸的最长公共子序列...方案存一下转移路径倒推就好了

复制代码
 1 #include<cstdio>
 2 #include<cstring>
 3 #define maxn 3005
 4 using namespace std;
 5 int dp[maxn][maxn],last[maxn][maxn];
 6 char s[maxn],t[maxn],w[maxn];
 7 int main(){
 8     scanf("%s%s",s+1,t+1);
 9     int n=strlen(s+1),m=strlen(t+1);
10     for (int i=1;i<=n;i++)
11     for (int j=1;j<=m;j++){
12         if (s[i]==t[j]) {
13             if (dp[i][j]<dp[i-1][j-1]+1) dp[i][j]=dp[i-1][j-1]+1,last[i][j]=1;
14         }
15         if (dp[i-1][j]>dp[i][j]) dp[i][j]=dp[i-1][j],last[i][j]=2;
16         if (dp[i][j-1]>dp[i][j]) dp[i][j]=dp[i][j-1],last[i][j]=3; 
17     }
18     int x=n,y=m;
19     while (dp[x][y]){
20         if (last[x][y]==1) w[dp[x][y]]=s[x],x--,y--;else
21         if (last[x][y]==2) x--;else y--;
22     }
23     for (int i=1;i<=dp[n][m];i++)
24     printf("%c",w[i]);
25     printf("\n");
26     return 0;
27 }
F
复制代码

G - Longest Path

最长路径,拓扑上dp

复制代码
 1 #include<cstdio>
 2 #define maxn 100050
 3 #define max(a,b) ((a)>(b)?(a):(b))
 4 using namespace std;
 5 struct enode{
 6     int nxt,y;
 7 }e[maxn];
 8 int ans=0,tot=0;
 9 int n,m;
10 int q[maxn],dp[maxn],first[maxn],goin[maxn];
11 void adde(int x,int y){
12     e[tot].nxt=first[x];
13     e[tot].y=y;
14     first[x]=tot++;
15     goin[y]++;
16 }
17 void tupu(){
18     int head=1,tail=0;
19     for (int i=1;i<=n;i++)
20     if (!goin[i]) q[++tail]=i;
21     while (head<=tail){
22         int x=q[head++];
23         if (dp[x]>ans) ans=dp[x];
24         for (int i=first[x];i>=0;i=e[i].nxt){
25             int y=e[i].y;
26             goin[y]--;
27             dp[y]=max(dp[x]+1,dp[y]);
28             if (!goin[y]) q[++tail]=y;
29         }
30     }
31 }
32 int main(){
33 
34     scanf("%d%d",&n,&m);
35     for (int i=1;i<=n;i++)
36     first[i]=-1;
37     for (int i=1;i<=m;i++){
38         int x,y;
39         scanf("%d%d",&x,&y);
40         adde(x,y);
41     }
42     tupu();
43     printf("%d\n",ans);
44         return 0;
45 }
G
复制代码

H - Grid 1

唔...入门dp吧QAQ

复制代码
 1 #include<cstdio>
 2 #define HR 1000000007
 3 using namespace std;
 4 char s[1005];
 5 int dp[1005][1005];
 6 int main(){
 7     int n,m;
 8     scanf("%d%d",&n,&m);
 9     dp[1][1]=1;
10     for (int i=1;i<=n;i++){
11         scanf("%s",s+1);
12         for (int j=1;j<=m;j++)
13         if ((i!=1||j!=1)&&(s[j]!='#')) dp[i][j]=(dp[i-1][j]+dp[i][j-1])%HR;
14     }
15     printf("%d\n",dp[n][m]);
16     return 0;
17 }
H
复制代码

I - Coins

概率dp

dp[i][j] 表示前 i 个有 j 个向上的概率

那么对于当前这一个 要不然就向上 要不然就向下

dp[i][j]=dp[i1][j1]p[i]+dp[i1][j](1p[i])

复制代码
 1 #include<cstdio>
 2 using namespace std;
 3 double p[3005],dp[3005][3005];
 4 int main(){
 5     int n;
 6     scanf("%d",&n);
 7     for (int i=1;i<=n;i++)
 8     scanf("%lf",&p[i]);
 9     dp[0][0]=1;
10     for (int i=1;i<=n;i++){
11         dp[i][0]=dp[i-1][0]*(1-p[i]);
12         for (int j=1;j<=i;j++)
13         dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[i]);
14     }
15     
16     double ans=0;
17     for (int i=1;i<=n;i++)
18     if (i>n-i) ans+=dp[n][i];
19     printf("%.10lf\n",ans);
20     return 0;
21 }
I
复制代码

J - Sushi

期望dp

dp[i][j][k] 表示 1i 个,2j 个,3k 个的期望

dp[i][j][k]=dp[i1][j][k]×in+dp[i+1][j1][k]×jn+dp[i][j+1][k1]×kn+dp[i][j][k]×nijkn+1

 

dp[i][j][k]×i+j+kn=dp[i1][j][k]×in+dp[i+1][j1][k]×jn+dp[i][j+1][k1]×kn+1


dp[i][j][k]×(i+j+k)=dp[i1][j][k]×i+dp[i+1][j1][k]×j+dp[i][j+1][k1]×k+n


dp[i][j][k]=dp[i1][j][k]×ii+j+k+dp[i+1][j1][k]×ji+j+k+dp[i][j+1][k1]×ki+j+k+ni+j+k

 

复制代码
 1 #include<cstdio>
 2 using namespace std;
 3 double dp[305][305][305];
 4 int a[5];
 5 int main(){
 6     int n;
 7     scanf("%d",&n);
 8     for (int i=1;i<=n;i++){
 9         int x;
10         scanf("%d",&x);
11         a[x]++;
12     }
13     for (int k=0;k<=n;k++)
14     for (int j=0;j<=n;j++)
15     for (int i=0;i<=n;i++)
16     if (i||j||k) {
17         if (i) dp[i][j][k]+=dp[i-1][j][k]*i/(i+j+k);
18         if (j) dp[i][j][k]+=dp[i+1][j-1][k]*j/(i+j+k);
19         if (k) dp[i][j][k]+=dp[i][j+1][k-1]*k/(i+j+k);
20         dp[i][j][k]+=(double)n/(i+j+k);
21     }
22     printf("%.15lf\n",dp[a[1]][a[2]][a[3]]);
23     return 0;
24 } 
25 
26 /*
27 dp[i][j][k]表示当前有i个1 j个2 k个3 的期望步数
28 
29 dp[0][0][0]=0
30 
31 dp[i][j][k]=dp[i-1][j][k]*i/n+dp[i+1][j-1][k]*j/n+dp[i][j+1][k-1]*k/n+dp[i][j][k]*(n-i-j-k)/n+1
32 dp[i][j][k]*(i+j+k)/n=dp[i-1][j][k]*i/n+dp[i+1][j-1][k]*j/n+dp[i][j+1][k-1]*k/n+1
33 dp[i][j][k]*(i+j+k)=dp[i-1][j][k]*i+dp[i+1][j-1][k]*j+dp[i][j+1][k-1]*k+n
34 dp[i][j][k]=dp[i-1][j][k]*i/(i+j+k)+dp[i+1][j-1][k]*j/(i+j+k)+dp[i][j+1][k-1]*k/(i+j+k)+n/(i+j+k)
35 
36 */
J
复制代码

 

posted @   Bunnycxk  阅读(741)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示