zoukankan      html  css  js  c++  java
  • 逢低吸纳Buy Low, Buy Lower/低价购买

    洛咕

    双倍经验

    题意:给定N(N<=5000)个数的序列,求出最长下降子序列的长度及方案数.

    分析:第一问最长下降子序列长度可以直接(O(N^2))求,设(f[i])表示枚举到第i位(即以第i个元素结尾)的最长上升子序列的长度:

    	for(int i=1;i<=n;i++){
    		f[i]=1;
    		for(int j=1;j<i;j++)
    	    	if(a[j]>a[i])
                	f[i]=max(f[i],f[j]+1);
    		ans=max(ans,f[i]);
        }
    

    考虑第二问怎么求?设(g[i])表示以第i个元素结尾的最长上升子序列的方案数.

    	for(int i=1;i<=n;i++){
            if(f[i]==1)g[i]=1;//初始化
            for(int j=1;j<i;j++){
                if(a[i]<a[j]&&f[i]==f[j]+1)
                	g[i]+=g[j];
    //如果i可以由j转移过来,则以a[i]结尾的方案数可以加上以a[j]结尾的方案数
                if(a[i]==a[j]&&f[i]==f[j])
                	f[j]=0;
    //如果i和j的元素值相等且以其结尾的最长下降子序列也相等,那么需要去重令f[j]=0(为什么是去掉j,而不是i?因为j在i前面,那么能够转移到j的也必定能够转移到i,也就是说i比j要优)
    
            }
        }
    

    第九个数据点要写高精模板,看到讨论里面说double可以水过去,我反正是没过得去,只能乖乖kuai高精.

    #include<bits/stdc++.h>
    #define rg register int
    #define ll long long
    using namespace std;
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int N=5005;
    int a[N],f[N];
    struct Van{
        
        bool fu; //是否是负数
        int tt,mod; //高精的长度
        int s[1005]; //压位用的数组
        
        inline Van(){ //整体初始化
            fu=0; tt=0; mod=1e9;
            memset(s,0,sizeof(s));
        }
        
        inline Van read(){  register char ch; //高精度读入
            while(!isdigit(ch=getchar()))if(ch=='-')fu=1;
            char _[100005]; rg l=0,r=-1; _[0]=ch;
            while(isdigit(_[++l]=getchar()));; tt=l/9-!(l%9);
            for(rg i=(l-1)%9+1;i;--i) (s[tt]*=10)+=_[++r]^48;
            for(rg i=tt-1;i>=0;--i)for(rg j=0;j<9;++j)(s[i]*=10)+=(_[++r]^48);
            while(tt&&!s[tt])--tt;; return (*this);
        }
        inline void print(){ //高精度输出
            if(fu)putchar('-');
            printf("%d",s[tt]);
            for(rg i=tt-1;i>=0;--i)
                printf("%09d",s[i]);
            putchar('
    ');
        }
    
        inline bool operator >(const Van &x){ //定义大于
            if(tt!=x.tt)return tt>x.tt;
            for(rg i=tt;i>=0;--i)
                if(s[i]!=x.s[i])return s[i]>x.s[i];
            return 0;
        }
        inline bool operator <(const Van &x){ //定义小于
            if(tt!=x.tt)return tt<x.tt;
            for(rg i=tt;i>=0;--i)
                if(s[i]!=x.s[i])return s[i]<x.s[i];
            return 0;
        }
    
        inline Van operator =(int x){ //int的等于
            while(tt)s[tt]=0,--tt;
            s[0]=x%mod; s[1]=x/mod;
            if(s[1])tt=1;; return *this;
        }
        inline Van operator =(ll x){ //ll的等于
            while(tt)s[tt]=0,--tt;
            while(x)s[tt]=x%mod,x/=mod,++tt;
            if(!s[tt])--tt;; return *this;
        }
    
        inline void add(const Van &x){ //加法的底层
            rg sign=0; if(x.tt>tt)tt=x.tt;
            for(rg i=0;i<=tt;++i){
                s[i]+=x.s[i]+sign; sign=0;
                if(s[i]>mod)s[i]-=mod,sign=1;
            }if(sign)s[++tt]=1;
        }
    
        inline void cut(const Van &x){ //减法的底层
            rg sign=0; 
            for(rg i=0;i<=tt;++i){
                s[i]-=x.s[i]+sign; sign=0;
                if(s[i]<0)s[i]+=mod,sign=1;
            }while(tt&&!s[tt])--tt;
            if(!tt&&!s[tt]) fu=0;
        }
    
        inline void mul(const Van &x){ //乘法的底层
            Van y; ll num; y.tt=tt+x.tt;
            for(rg i=0;i<=tt;++i){ num=0;
                for(rg j=0;j<=x.tt;++j){
                    num=(ll)s[i]*x.s[j]+y.s[j+i]+num;
                    y.s[j+i]=num%mod; num/=mod;
                } if(num)y.s[x.tt+i+1]=num;
            }if(num)++y.tt;; *this=y;
        }
    
        inline void operator +=(Van x){ //赋值加法重载
            if(fu==x.fu){(*this).add(x); return;}
            if(*this>x) (*this).cut(x);
            else x.cut(*this),*this=x,fu^=1;
        }
        inline Van operator +(const Van &x){ //加法正常重载
            Van y=*this; y+=x; return y;
        }
        
        inline void operator -=(Van x){ //赋值减法重载
            if(fu!=x.fu){(*this).add(x); return;}
            if(*this>x){(*this).cut(x); return;}
            x.cut(*this); *this=x; if(s[tt])fu^=1;
        }
        inline Van operator -(const Van &x){ //减法正常重载
            Van y=*this; y-=x; return y;
        }
        
        inline void operator *=(Van x){ //赋值乘法重载
            if(!s[tt]||!x.s[x.tt]){Van y; *this=y;}
            if(fu!=x.fu)fu=1;else fu=0;; (*this).mul(x);
        }
        inline Van operator *(const Van &x){ //乘法正常重载
            Van y=*this; y*=x; return y;
        }
    
        inline Van operator *(int x){  Van y; y=x; return (*this)*y;}
        inline void operator *=(int x){Van y; y=x; (*this)*=y;}
        inline Van operator +(int x){  Van y; y=x; return (*this)+y;}
        inline void operator +=(int x){Van y; y=x; (*this)+=y;}
        inline Van operator -(int x){  Van y; y=x; return (*this)-y;}
        inline void operator -=(int x){Van y; y=x; (*this)-=y;}
    }Ans,g[N];
    int main(){
        int n=read(),ans=0;
        for(int i=1;i<=n;i++)a[i]=read();
        for(int i=1;i<=n;i++){
    		f[i]=1;
    		for(int j=1;j<i;j++)
    	    	if(a[j]>a[i])f[i]=max(f[i],f[j]+1);
    		ans=max(ans,f[i]);
        }
        printf("%d ",ans);
        for(int i=1;i<=n;i++){
            if(f[i]==1)g[i]=1;
            for(int j=1;j<i;j++){
                if(a[i]<a[j]&&f[i]==f[j]+1)
                	g[i]=g[i]+g[j];
                if(a[i]==a[j]&&f[i]==f[j])
                	f[j]=0;
            }
        }
        for(int i=1;i<=n;i++)
            if(f[i]==ans)Ans+=g[i];
        Ans.print();
        return 0;
    }
    
    
  • 相关阅读:
    实反对称矩阵正则化
    小矩阵相乘效率对比:lapack, cblas, 手写函数
    python实现: VMC做一维谐振子
    一个简单矩阵的本征值问题
    python画能级图
    广义相对论笔记
    PVPC kb3g pn/upn Ti44 LAP 脚本
    自组织临界现象:沙堆模型
    c#备份MySQL数据库 转载 from
    vs2010 新特性 from
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10992736.html
Copyright © 2011-2022 走看看