zoukankan      html  css  js  c++  java
  • 动态规划训练之六

    https://www.luogu.org/problem/P2467

    这是一道好题

    题目描述

    求1-n排列组成的波动数列的个数

    分析首先肯定是个dp没错了,考虑设计方案,

    dp[i,j],表示用1-i的排列最后一个为j的方案数

    dp[i,j]相当于dp[i-1,k]中原排列大于等于j的数都加1,再把j插到末尾后的新合法排列的方案数

    类似test10.7的排列题

    答案有“M"型与"W"型,显然方案数是一样的,这里只考虑"W"型的,最后把答案*2就行了

    这时你可能会有疑问,为什么偶数是枚举[1,j-1],而奇数是枚举[j,i-1],

    因为只考虑“W”形态的,所以奇数一定是山峰的,而偶数一定山谷

    所以奇数枚举的一定要比前一个位置上的数大,偶数枚举的一定要比前一个位置上的数小

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 4211
    #define M(a) ((a)<=mod?(a):(a-mod))
    inline int read(){
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        return x*f;
    }
    int n,mod;
    int dp[N][N],ans=0;
    int main(){
        n=read(),mod=read();
        for(int i=1;i<=n;i++){
            dp[1][i]=1;
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i&1){
                    for(int k=j;k<i;k++){
                        dp[i][j]=M(dp[i][j]+dp[i-1][k]); 
                    }
                }
                else{
                    for(int k=1;k<j;k++){
                        dp[i][j]=M(dp[i][j]+dp[i-1][k]);
                    }
                }
            }
        }
        for(int i=1;i<=n;i++){
            ans=M(ans+dp[n][i]);
        } 
        cout<<2*ans%mod<<endl;
        return 0;
    }
    

    下面的代码是用树状数组维护的,实际上可以用前缀和就好(代码不是我写的,不然我肯定前缀和)
    还有就是要开O2才能过
    code by std:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define N 4211
    #define M(a) ((a)<=mod?(a):(a-mod))
    inline int read(){
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        return x*f;
    }
    int n,mod;
    int dp[N][N],ans=0;
    int b[N];
    int lowbit(int x){
        return x&(-x);
    }
    void Add(int x,int d){
        while(x<=n){
            b[x]=M(b[x]+d);
            x+=lowbit(x);
        }
    }
    int Ask(int x){
        int ans=0;
        while(x){
            ans=M(ans+b[x]);
            x-=lowbit(x);
        }
        return ans;
    }
    int main(){
        n=read(),mod=read();
        for(int i=1;i<=n;i++){
            dp[1][i]=1;
            Add(i,1);
        }
        for(int i=2;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i&1){
                    if(i>j){
                        dp[i][j]=M(Ask(i-1)-Ask(j-1)+mod);
                    }
                }
                else{
                    dp[i][j]=Ask(j-1);
                }
            }
            memset(b,0,sizeof(b));
            for(int j=1;j<=n;j++){
                Add(j,dp[i][j]);
            }
        }
        for(int i=1;i<=n;i++){
            ans=M(ans+dp[n][i]);
        } 
        cout<<2*ans%mod<<endl;
        return 0;
    }
    
  • 相关阅读:
    C++雾中风景1:友元类与面向对象
    NFS服务器的安装与配置
    未来工作相关
    python 函数
    pycharm、sublime个性化设置
    hadoop中HDFS的NameNode原理
    Cat搭建遇坑记
    美团点评CAT监控平台研究
    阿里sentinel源码研究深入
    阿里熔断限流Sentinel研究
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11638177.html
Copyright © 2011-2022 走看看