说好从今以后要牵着手,因为要走很远.|

洛浔

园龄:4年3个月粉丝:13关注:10

📂题解
🔖DP
2023-04-30 14:51阅读: 39评论: 0推荐: 0

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 个。
则有 dpi,j,k=1+dpi,j,knijkn+dpi1,j,kin+dpi+1,j1,kjn+dpi,j+1,k1kn
简单化一下式子 ndpi,j,k=n+dpi,j,k(nijk)+dpi1,j,ki+dpi+1,j1,kj+dpi,j+1,k1k
这傻逼练 latex 呢是吧 (i+j+k)dpi,j,k=n+dpi1,j,ki+dpi+1,j1,kj+dpi,j+1,k1k
dpi,j,k=n+dpi1,j,ki+dpi+1,j1,kj+dpi,j+1,k1ki+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;
}

L

简单区间 DP

// Problem: Deque
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_dp_l
// Memory Limit: 1 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
int n;
long long a[3005],dp[3005][3005];

int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)dp[i][i]=a[i];
    for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int l=i,r=i+len-1;
            dp[l][r]=max(a[l]-dp[l+1][r],a[r]-dp[l][r-1]);
        }
    }
    cout<<dp[1][n];    
    return 0;
}

M

简单 dp

// Problem: Candies
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_dp_m
// Memory Limit: 1 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,dp[100005],sum[100005],k;
int a[105];
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];
    dp[0]=1;for(int i=0;i<=k;i++)sum[i]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++)
            dp[j]=((sum[j]-(((j-a[i])<=0)?0:sum[j-a[i]-1]))+mod)%mod;
        // for(int j=1;j<=k;j++)cout<<dp[j]<<" ";cout<<endl;
        for(int j=1;j<=k;j++)sum[j]=sum[j-1]+dp[j],sum[j]%=mod;
    }
    cout<<dp[k];
    return 0;
}

N

板子 但是学了一下高级做法。

// Problem: P5569 [SDOI2008] 石子合并
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5569
// Memory Limit: 125 MB
// Time Limit: 1000 ms

#include<bits/stdc++.h>
using namespace std;
#define int long long
main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,k,j,ans=0,sum;
    vector<int> v;
    cin>>n;
    v.push_back(LONG_LONG_MAX-10);
    for(int i=1,tmp;i<=n;i++) cin>>tmp,v.push_back(tmp);
    v.push_back(LONG_LONG_MAX-10);
    while(n-->1){
        for(k=1;k<=n;k++)if(v[k-1]<v[k+1]) break;
        int tmp=v[k]+v[k-1];
        for(j=k-1;j>=0;j--) if(v[j]>=v[k]+v[k-1])break;
        v.erase(v.begin()+k-1);
        v.erase(v.begin()+k-1);
        v.insert(v.begin()+j+1,tmp);
        ans+=tmp;
        // cout<<tmp<<endl;
    }
    cout<<ans<<endl;
    return 0;
}

O

给定二分图,求完美匹配数,n21

看数据范围就挺状压的。然后状压显然的性质就是包含这个东西的在它之后转移就是数的大小嘛
这个 f 表示的是前 popcount(i) 个人许配给了集合 Si

// Problem: Matching
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_dp_o
// Memory Limit: 1 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
const int N=1<<21;
int n,ma,mp[33][33];
int f[N];
const int mod=1e9+7;
int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=0;i<n;i++)for(int j=0;j<n;j++)cin>>mp[i][j];
    ma=1<<n;ma--;
    f[0]=1;
    for(int i=0;i<=ma;i++){
        int len=__builtin_popcount(i);
        
        for(int j=0;j<n;j++)
        if((!(i&(1<<j)))&&mp[len][j])(f[i|(1<<j)]+=f[i])%=mod;
    }
    cout<<f[ma];
    return 0;
}

P

树形 dp 板子,注意方案数用乘法原理。

// Problem: Independent Set
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_dp_p
// Memory Limit: 1 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5,mod=1e9+7;
int n,dp[N][2];
vector<int> v[N];
void dfs(int u,int fa){
    dp[u][0]=dp[u][1]=1;
    for(int to:v[u]){
        if(to==fa)continue;
        dfs(to,u);
        (dp[u][0]*=((dp[to][0]+dp[to][1])%mod))%=mod;
        (dp[u][1]*=dp[to][0])%=mod;
    }
}
signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        int f,t;
        cin>>f>>t;
        v[f].push_back(t);v[t].push_back(f);
        // cout<<f<<" "<<t<<endl;
    }
    dfs(1,0);
    // for(int i=1;i<=n;i++)cout<<dp[i][0]<<" "<<dp[i][1]<<endl;
    cout<<(dp[1][0]+dp[1][1])%mod;
    return 0;
}

本文作者:洛浔

本文链接:https://www.cnblogs.com/Artemis-lx/p/17365290.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   洛浔  阅读(39)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起