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的主要内容,如果未能解决你的问题,请参考以下文章

Educational DP Contest S-Digit Sum(数位dp)

Educational Codeforces Round 63-D(基础DP)

Educational Codeforces Round 76 (Rated for Div. 2) E. The Contest

Educational Codeforces Round 80 C. Two Arrays

Educational Codeforces Round 73 (Rated for Div. 2) D. Make The Fence Great Again(DP)

Educational Codeforces Round 59 (Rated for Div. 2) E 区间dp + 状态定义