• dp practice 1


    https://codeforces.com/problemset/problem/553/A

    dp+组合数学

    dp[i] 放前i种颜色的方法数

     #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e3+7;
    const ll mod = 1e9+7;
    int a[N];
    ll dp[N],f[N];
    void work(){
        f[0]=1;
        f[1]=1;
        for(int i=2;i<N;i++)
            f[i]=f[i-1]*i%mod;
    }
    ll q_pow(ll a,ll n){
        ll ans=1; ll base=a;
        while(n){
            if(n&1) ans=(ans*base)%mod;
            base=base*base%mod;
            n>>=1;
        }
            return ans;
    }
    ll inv(ll a,ll b){
        return q_pow(a,b-2);
    } 
    ll C(int n,int m){
        return f[n]*inv(f[n-m]*f[m]%mod,mod)%mod;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int k; cin>>k;
        for(int i=1;i<=k;i++){
            cin>>a[i];    
        }
        work();
        int sum=a[1];
        dp[1]=1;
        for(int i=2;i<=k;i++){
            dp[i]=(dp[i-1]*C(sum+a[i]-1,a[i]-1))%mod;
            sum+=a[i];
        }
        cout<<dp[k]<<endl;
        return 0;
    }
    View Code

    https://codeforces.com/problemset/problem/264/B

    dp+简单数论

    dp[i] 表示当前当前位置因子为i的所能构成的序列长度

     #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+7;
    const ll mod = 1e9+7;
    int a[N];
    int dp[N];
    vector<int> v[N];
    void work(){
        for(int i=2;i<N;i++)
            for(int j=i;j<N;j+=i)
                v[j].push_back(i);
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int n; cin>>n;
        work();
        for(int i=1;i<=n;i++) cin>>a[i];
        v[1].push_back(1);
        for(int i=1;i<=n;i++){
            int tmp=0;
            for(int j=0;j<v[a[i]].size();j++)
                tmp=max(tmp,dp[v[a[i]][j]]);
            for(int j=0;j<v[a[i]].size();j++)
                dp[v[a[i]][j]]=tmp+1;
        }
        int ans=0;
        for(int i=1;i<N;i++) ans=max(ans,dp[i]);
        cout<<ans<<endl; 
        return 0;
    }
    View Code

     http://codeforces.com/contest/339/problem/C

    dp+路径还原

    dp[i][j] 表示用了j克的砝码 变成了重量为i 是否存在

    #include <bits/stdc++.h>
    using namespace std;
    const double pi = acos(-1.0);
    const int N = 2e5+7;
    const int inf = 0x3f3f3f3f;
    const double eps = 1e-6;
    typedef long long ll;
    typedef pair<int,int> pii;
    const ll mod = 1e9+7;
    vector<int> w;
    int dp[207][15];
    pii path[1007][207][15];
    void find(int x,int y,int cnt){
        if(cnt==0) return ;
        find(path[cnt][x][y].first,path[cnt][x][y].second,cnt-1);
        cout<<y<<" ";
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        string s; cin>>s;
        for(int i=0;i<10;i++) if(s[i]=='1') w.push_back(i+1);
        int m; cin>>m;
        int fix=100;
        for(int i=0;i<w.size();i++){
            dp[fix+w[i]][w[i]]=1;
            path[1][fix+w[i]][w[i]]=make_pair(fix,0);
        }
        for(int i=2;i<=m;i++){
            if(i&1){
                for(int j=fix-50;j<fix;j++)
                    for(int k=0;k<w.size();k++)
                        if(dp[j][w[k]]){
    //                        cout<<j<<" "<<w[k]<<endl;
                            for(int l=0;l<w.size();l++){
    //                            cout<<j<<" "<<fix<<endl; 
                                if(w[l]==w[k]||j+w[l]<=fix) continue;
                                dp[j+w[l]][w[l]]=1;
                                path[i][j+w[l]][w[l]]=make_pair(j,w[k]); 
                            }
                            dp[j][w[k]]=0;
                        }
            }else{
            //    cout<<"11"<<endl;
                for(int j=fix+1;j<=fix+1+50;j++)
                    for(int k=0;k<w.size();k++)
                        if(dp[j][w[k]]){
                        //    cout<<j<<" "<<w[k]<<endl;
                            for(int l=0;l<w.size();l++){
                                if(w[l]==w[k]||j-w[l]>=fix) continue;
                                dp[j-w[l]][w[l]]=1;
                            //    cout<<j-w[l]<<endl;
                                path[i][j-w[l]][w[l]]=make_pair(j,w[k]);
                            }
                            dp[j][w[k]]=0;
                        }
            }
        }
        if(m&1){
            int x=-1,y=-1;
            for(int i=fix+1;i<fix+1+50;i++)
                for(int j=0;j<w.size();j++)
                    if(dp[i][w[j]]){
                        x=i; y=w[j];
                        break;
                    }
            if(x==-1){
                cout<<"NO
    ";
            }else{
                cout<<"YES
    ";
    //            cout<<x<<" "<<y<<endl;
                find(x,y,m);
                cout<<"
    ";
            }
        }else{
            int x=-1,y=-1;
            for(int i=fix-50;i<fix;i++)
                for(int j=0;j<w.size();j++)
                    if(dp[i][w[j]]){
                        x=i; y=w[j];
                        break;
                    }
            if(x==-1){
                cout<<"NO
    ";
            }else{
                cout<<"YES
    ";
    //            cout<<x<<" "<<y<<endl;
                find(x,y,m);
                cout<<"
    ";
            }
        }
        return 0;
    }
    View Code

     https://codeforces.com/problemset/problem/977/F

    dp+路径

    dp[i]表示以i位置为结尾所能构成的最大连续个数 用一个map记录最后一个数为i的最大长度

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pi;
    const int N = 2e5+7;
    const ll mod = 1e9+7;
    int a[N],dp[N],path[N];
    map<int,pi> mm;
    vector<int> v;
    void find(int x){
        if(!x) return ;
        find(path[x]);
        v.push_back(x);
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int n; cin>>n;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++){
            if(mm.count(a[i]-1)){
                dp[i]=mm[a[i]-1].first+1;
                mm[a[i]]=make_pair(dp[i],i);
                path[i]=mm[a[i]-1].second;
            }else{
                dp[i]=1;
                mm[a[i]]=make_pair(1,i);
            }
        }
        int ans=0; int xx;
        for(int i=1;i<=n;i++){
            if(dp[i]>ans){
                ans=dp[i];
                xx=i;
            }
        }
        find(xx);
        cout<<ans<<"
    ";
        for(int i=0;i<v.size();i++)
            cout<<v[i]<<" ";
        cout<<"
    ";
        return 0;
    }
    View Code

     https://codeforces.com/problemset/problem/711/C

    dp[i][j][k] 表示前i个位置 最后一个数颜色为j 且分为k组的最小花费

    #include <bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const double eps = 1e-6;
    const int N = 4e5+7;
    typedef long long ll;
    const ll mod = 1e9+7;
    using namespace std;
    int a[107];
    ll cost[107][107];
    ll dp[107][107][107];
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int n,m,k; cin>>n>>m>>k;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                cin>>cost[i][j];
        memset(dp,0x3f3f3f3f3f3f3f3f,sizeof(dp));
        for(int i=1;i<=n;i++){
            for(int kk=1;kk<=k;kk++){
                if(kk>i) break;
                if(a[i]){
                    if(i==1){
                        dp[i][a[i]][1]=0;
                        continue;
                    }
                    dp[i][a[i]][kk]=dp[i-1][a[i]][kk];
                    for(int j=1;j<=m;j++){
                        if(j==a[i]) continue;
                        dp[i][a[i]][kk]=min(dp[i][a[i]][kk],dp[i-1][j][kk-1]);
                    }
                }else{
                    if(i==1){
                        for(int j=1;j<=m;j++)
                            dp[i][j][1]=cost[1][j];
                        continue;
                    }
                    for(int j=1;j<=m;j++){
                        dp[i][j][kk]=dp[i-1][j][kk]+cost[i][j];
                        for(int l=1;l<=m;l++){
                            if(j==l) continue;
                            dp[i][j][kk]=min(dp[i][j][kk],dp[i-1][l][kk-1]+cost[i][j]);
                        }
                    }        
                }
            }
        }
        ll ans=0x3f3f3f3f3f3f3f3f;
        for(int i=1;i<=m;i++)
            ans=min(ans,dp[n][i][k]);
        if(ans==0x3f3f3f3f3f3f3f3f) cout<<"-1"<<endl;
        else cout<<ans<<endl;
        return 0;
    }
    View Code

     http://codeforces.com/problemset/problem/279/C

    dp[i][j]表示当前升上去或者降下来的最左点

    #include <bits/stdc++.h>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const double eps = 1e-6;
    const int N = 1e5+7;
    typedef long long ll;
    const ll mod = 1e9+7;
    using namespace std;
    int a[N];
    int dp[N][2];
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
        int n,m; cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>a[i];
        dp[1][0]=1; dp[1][1]=1;
        for(int i=2;i<=n;i++){
            if(a[i]<a[i-1]){
                dp[i][0]=i;
                dp[i][1]=dp[i-1][1];
            }else if(a[i]>a[i-1]){
                dp[i][0]=dp[i-1][0];
                dp[i][1]=i;
            }else{
                dp[i][0]=dp[i-1][0];
                dp[i][1]=dp[i-1][1];
            }
        }
        for(int i=1;i<=m;i++){
            int l,r; cin>>l>>r;
            if(l<min(dp[dp[r][1]][0],dp[r][0])){
                cout<<"No
    ";
            }else{
                cout<<"Yes
    ";
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    IDEA学习和收藏夹
    mysql资料收集及学习
    一些模板代码
    docker学习
    Spring事务传播类型
    rust学习疑惑
    [重新做人]从头学习JAVA SE——java.lang.reflect
    java核心技术卷一
    Spring实战 难懂的JavaBean
    Spring实战系列
  • 原文地址:https://www.cnblogs.com/wmj6/p/11503193.html
Copyright © 2020-2023  润新知