Educational DP Contest

Posted 洛浔的小窝喵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational DP Contest相关的知识,希望对你有一定的参考价值。

Educational DP Contest

Educational DP Contest

ATcoder_link
夯实基础的好东西

I

记录一下此时第 i 个有多少概率小于等于 j 的就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N=3005;
#define db double 
db dp[N][N];
int n;
db p[N];
int main()
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>p[i];
    int ma=n/2;
    for(int i=0;i<=ma;i++) dp[0][i]=1;
    for(int i=1;i<=n;i++)
        db f=1-p[i],z=p[i];
        dp[i][0]=dp[i-1][0]*z;
        for(int j=1;j<=ma;j++) dp[i][j]=dp[i-1][j]*z+dp[i-1][j-1]*f;
    
    printf("%.10lf",dp[n][ma]);
    return 0;

J

期望的经典题型。
首先几个盘子是等价的设 \\(1,2,3\\) 分别有 \\(i,j,k\\) 个。
则有 \\(dp_i,j,k=1+dp_i,j,k*\\fracn-i-j-kn+dp_i-1,j,k*\\fracin+dp_i+1,j-1,k*\\fracjn+dp_i,j+1,k-1*\\frackn\\)
简单化一下式子 \\(n*dp_i,j,k=n+dp_i,j,k*(n-i-j-k)+dp_i-1,j,k*i+dp_i+1,j-1,k*j+dp_i,j+1,k-1*k\\)
这傻逼练 latex 呢是吧 \\((i+j+k)*dp_i,j,k=n+dp_i-1,j,k*i+dp_i+1,j-1,k*j+dp_i,j+1,k-1*k\\)
\\(dp_i,j,k=\\fracn+dp_i-1,j,k*i+dp_i+1,j-1,k*j+dp_i,j+1,k-1*ki+j+k\\)

然后注意下转移顺序就可以了喵。感觉有助于理解期望。
可能比较抽象:期望是转移走的概率,就是每个可能性的期望*概率,所以要从简单向复杂的推,从复杂的往简单的推应该能做但是式子未免太抽象了。反过来是好的!

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=305;
#define db double
db dp[N][N][N];
int n;
int cnt[5];
int main()
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
        int tmp;
        cin>>tmp;
        cnt[tmp]++;
    
    for(int k=0;k<=n;k++)
        for(int j=0;j<=n;j++)
        for(int i=0;i<=n;i++)
            if(i||j||k)
                if(i)dp[i][j][k]+=dp[i-1][j][k]*i;
                if(j)dp[i][j][k]+=dp[i+1][j-1][k]*j;
                if(k)dp[i][j][k]+=dp[i][j+1][k-1]*k;
                (dp[i][j][k]+=n)/=(i+j+k);
            
        
    
    cout<<dp[cnt[1]][cnt[2]][cnt[3]];
    return 0;

K

经典博弈题,如果一个点能到达必胜状态它就是必胜的。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int f[100005];
int a[105];
int n,k;
int main()
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=k;i++)
        for(int j=1;j<=n;j++)
        f[i]|=((i-a[j]>=0)&&(!f[i-a[j]]));
    
    puts(f[k]?"First":"Second");
    return 0;

Educational Codeforces Round 63-D(基础DP)

题目链接:https://codeforces.com/contest/1155/problem/D

题意:给定n个数,可以选择一段连续子段将其乘x,也可以不操作,求最大连续子段和。

思路:比赛时觉得是dp,但怎么也想不出来QAQ,dp太难了。。。赛后看了别人题解,找到状态和转移方程就很简单了,然而比赛时我就是想不到。。。

考虑下标i:有3种情况,可能[0,i]都没有乘x,可能i乘了x,可能[i,n]都不会乘x。分别用dp[i][0]表示以i结尾的最长子段和且 [0,i]都没乘x,dp[i][1]表示以i结尾的最长子段和且i要乘x,dp[i][2]表示以i结尾的最长子段和且[i,n]都不会乘x。

则状态转移方程为:dp[i][0]=max(dp[i-1],0)+a[i];

         dp[i][1]=max(dp[i-1][0],dp[i-1][1],0)+a[i]*x;

         dp[i][2]=max(dp[i-1][1],dp[i-1][2],0)+a[i];

加油!!下一次会更好!

AC代码:

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;

int n,x;
LL dp[300005][3],ans;

int main(){
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;++i){
        LL tmp;
        scanf("%lld",&tmp);
        dp[i][0]=max(dp[i-1][0],0LL)+tmp;
        dp[i][1]=max(dp[i-1][0],max(dp[i-1][1],0LL))+1LL*tmp*x;
        dp[i][2]=max(dp[i-1][1],max(dp[i-1][2],0LL))+tmp;
        ans=max(ans,max(dp[i][0],max(dp[i][1],dp[i][2])));
    }
    printf("%lld\n",ans);
    return 0;
}

 

以上是关于Educational DP Contest的主要内容,如果未能解决你的问题,请参考以下文章