atcoder dp题单刷穿

题单传送门 26道题目

F

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e3+10;
int n,m,f[N][N];
string a,b;
void dfs(int i,int j){
    
    
    if(i==0||j==0)return;
    if(a[i]==b[j]){
    
    
        dfs(i-1,j-1);
        cout<<a[i];
    }
    else{
    
    
        if(f[i][j-1]>=f[i-1][j])dfs(i,j-1);
        else dfs(i-1,j);
    }
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>a>>b;
    int n=a.length(),m=b.length();
    a=" "+a;
    b=" "+b;
    for(int i=1;i<=n;i++){
    
    
        for(int j=1;j<=m;j++){
    
    
            f[i][j]=max(f[i-1][j],f[i][j-1]);
            if(a[i]==b[j]){
    
    
                f[i][j]=max(f[i][j],f[i-1][j-1]+1);
            }
        }
    }
    dfs(n,m);
}

J

有效打击的概率是 非 0 寿司数 / n 非0寿司数/n 0寿司数/n
期望就是倒数

记录i,j,k分别表示寿司数为1,2,3的数目
i / ( i + j + k ) 的有效打击会用于寿司数为 1 上 i/(i+j+k)的有效打击会用于寿司数为1上 i/(i+j+k)的有效打击会用于寿司数为1
j / ( i + j + k ) 的有效打击会用于寿司数为 2 上 j/(i+j+k)的有效打击会用于寿司数为2上 j/(i+j+k)的有效打击会用于寿司数为2
k / ( i + j + k ) 的有效打击会用于寿司数为 3 上 k/(i+j+k)的有效打击会用于寿司数为3上 k/(i+j+k)的有效打击会用于寿司数为3

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=301;
int n,a[4];
double f[N][N][N];
double dfs(int i,int j,int k){
    
    
    if(i==0&&j==0&&k==0)return 0;
    if(f[i][j][k]>0)return f[i][j][k];
    double sum=1.0*n/(i+j+k);
    if(i)sum+=dfs(i-1,j,k)*(1.0*i/(i+j+k));
    if(j)sum+=dfs(i+1,j-1,k)*(1.0*j/(i+j+k));
    if(k)sum+=dfs(i,j+1,k-1)*(1.0*k/(i+j+k));
    return f[i][j][k]=sum;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        int x;
        cin>>x;
        a[x]++;
    }
    printf("%.12lf",dfs(a[1],a[2],a[3]));
}

K

裸题sg博弈

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,k,a[110],f[N];
int dfs(int x){
    
    
    if(f[x]!=-1)return f[x];
    int ok=0;
    for(int i=1;i<=n;i++){
    
    
        if(x>=a[i])ok|=!dfs(x-a[i]);
    }
    return f[x]=ok;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>k;
    memset(f,-1,sizeof f);
    f[0]=0;
    for(int i=1;i<=n;i++)cin>>a[i],f[a[i]]=1;
    if(dfs(k))cout<<"First";
    else cout<<"Second";
}


L

记搜
d f s ( l , r , o p ) 表示我先手,我与对手的结果差值, dfs(l,r,op)表示我先手,我与对手的结果差值, dfs(l,r,op)表示我先手,我与对手的结果差值,
op=1表示要让结果最大化的那个先手者,op=0表示要让结果最小化的后手者

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e3+10;
int n,a[N],f[N][N][2];
int dfs(int l,int r,int op=1){
    
    
    if(l==r)return a[l];
    if(f[l][r][op]!=-1)return f[l][r][op];
    if(op)return f[l][r][op]=max(a[l]-dfs(l+1,r,1-op),-dfs(l,r-1,1-op)+a[r]);
    else  return f[l][r][op]=max(a[l]-dfs(l+1,r,1-op),-dfs(l,r-1,1-op)+a[r]);
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    memset(f,-1,sizeof f);
    int sum=0;
    for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
    cout<<dfs(1,n);
}

M

f [ i ] [ j ] = ∑ f [ i − 1 ] [ j 到 j − a [ i ] ] f[i][j] = ∑f[i-1][j到j-a[i]] f[i][j]=f[i1][jja[i]]
记录一下前缀和就好了

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=1e5+10;
int n,a[110],k;
int f[110][N],s[110][N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    f[0][0]=1;
    int i=0;
    s[i][0]=f[i][0];
    for(int j=1;j<=k;j++){
    
    
        s[i][j]=(s[i][j-1]+f[i][j])%mod;
    }
    for(int i=1;i<=n;i++){
    
    
        for(int j=0;j<=k;j++){
    
    
            int r=j;
            int l=j-a[i];
            if(l<=0)f[i][j]=s[i-1][r];
            else f[i][j]=s[i-1][r]-s[i-1][l-1];
            f[i][j]=(f[i][j]+mod)%mod;
        }
        s[i][0]=f[i][0];
        for(int j=1;j<=k;j++){
    
    
            s[i][j]=(s[i][j-1]+f[i][j])%mod;
        }
    }
    cout<<f[n][k];
}

猜你喜欢

转载自blog.csdn.net/supreme567/article/details/128531664
今日推荐