• 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
    ",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
    ",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
    ",ans);
    20     return 0;
    21 }
    D

    E - Knapsack 2

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

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

    答案就从大到小枚举 $leq 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
    ",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("
    ");
    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
    ",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
    ",dp[n][m]);
    16     return 0;
    17 }
    H

    I - Coins

    概率dp

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

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

    $dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[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
    ",ans);
    20     return 0;
    21 }
    I

    J - Sushi

    期望dp

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

    $dp[i][j][k]=dp[i-1][j][k] imes frac{i}{n}+dp[i+1][j-1][k] imes frac{j}{n}+dp[i][j+1][k-1] imes frac{k}{n}+dp[i][j][k] imes frac{n-i-j-k}{n}+1$

     

    $dp[i][j][k] imes frac{i+j+k}{n}=dp[i-1][j][k] imes frac{i}{n}+dp[i+1][j-1][k] imes frac{j}{n}+dp[i][j+1][k-1] imes frac{k}{n}+1$


    $dp[i][j][k] imes(i+j+k)=dp[i-1][j][k] imes i+dp[i+1][j-1][k] imes j+dp[i][j+1][k-1] imes k+n$


    $dp[i][j][k]=dp[i-1][j][k] imes frac{i}{i+j+k}+dp[i+1][j-1][k] imes frac{j}{i+j+k}+dp[i][j+1][k-1] imes frac{k}{i+j+k}+frac{n}{i+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
    ",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
  • 相关阅读:
    时间戳(UnixTimestamp)与 《2038年问题》
    端口相关命令
    Ubuntu中的在文件中查找和替换命令
    A Reusable Aspect for Memory Profiling
    acc文件的运行
    A Reusable Aspect for Memory Allocation Checking
    ACC常用语句
    aspectC++常用命令
    c++调用DOS命令,不显示黑屏
    fopen文件目录问题
  • 原文地址:https://www.cnblogs.com/Bunnycxk/p/11586466.html
Copyright © 2020-2023  润新知