zoukankan      html  css  js  c++  java
  • #749. 「NOIP2021模拟赛 By ZYQ A」你就是方新童学长吗 题解

    #749. 「NOIP2021模拟赛 By ZYQ A」你就是方新童学长吗

    sol

    这里要用到笛卡尔树,所以想了好久都没想到正解

    我们发现笛卡尔树有着非常优秀的性质,父节点的权值都比儿子大,左右儿子分别在序列两侧,所以和这道题的性质非常符合

    我们将序列建一颗笛卡尔树,然后考虑 \(DP\)

    定义 \(F[x][k]\) 表示第 \(x\) 号节点,在以这个节点为根的子树内取了 \(k\) 个点的最小 \(C_k\)

    然后考虑转移,枚举左右两个儿子的 \(k\) ,分别为 \(i,j\)

    因为 \(a[x]\) 在左右儿子之间且比左右儿子的所有节点都大,所以无论怎么样,都要加上跨过这个点的代价,即 \(a[x]\times i\times j\)

    然后考虑取这个点,加上的区间个数就是 \(i+j+1\) 代价都是 \(a[x]\) 那么总的代价就是 \(a[x]\times (i+j+1)\)

    code

    #include<bits/stdc++.h>
    #define min(a,b) (a<b?a:b)
    using namespace std;
    typedef long long LL;
    const int maxn=5e3+5;
    const LL INF=0x3F3F3F3F3F3F3F3F;
    struct node{
    	LL w;
    	int ls,rs,size;
    }a[maxn];
    int N;
    LL F[maxn][maxn];
    int st[maxn],top;
    struct IO{
        static const int S=1<<21;
        char buf[S],*p1,*p2;int st[105],Top;
        ~IO(){clear();}
        inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
        inline void pc(const char c){Top==S&&(clear(),0);buf[Top++]=c;}
        inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
        inline IO&operator >> (char&x){while(x=gc(),x==' '||x=='\n'||x=='\r');return *this;}
        template<typename T>inline IO&operator >> (T&x){
            x=0;bool f=0;char ch=gc();
            while(ch<'0'||ch>'9'){if(ch=='-') f^=1;ch=gc();}
            while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=gc();
            f?x=-x:0;return *this;
        }
        inline IO&operator << (const char c){pc(c);return *this;}
        template<typename T>inline IO&operator << (T x){
            if(x<0) pc('-'),x=-x;
            do{st[++st[0]]=x%10,x/=10;}while(x);
            while(st[0]) pc('0'+st[st[0]--]);return *this;
        }
    }fin,fout;
    void dfs(int x){
    	a[x].size=1;
    	if(a[x].ls) dfs(a[x].ls),a[x].size+=a[a[x].ls].size;
    	if(a[x].rs) dfs(a[x].rs),a[x].size+=a[a[x].rs].size;
    	for(int i=0;i<=a[a[x].ls].size;i++)
    	for(int j=0;j<=a[a[x].rs].size;j++){
    		F[x][i+j]=min(F[x][i+j],F[a[x].ls][i]+F[a[x].rs][j]+a[x].w*i*j);
    		F[x][i+j+1]=min(F[x][i+j+1],F[a[x].ls][i]+F[a[x].rs][j]+a[x].w*i*j+a[x].w*(i+j+1));
    	}
    }
    inline void build(){
    	for(int i=1;i<=N;i++){
    		while(top&&a[st[top]].w<a[i].w) a[i].ls=st[top--];
    		if(top) a[st[top]].rs=i;
    		st[++top]=i;
    	}
    	return ;
    }
    int main(){
    	freopen("A.in","r",stdin);
    	freopen("A.out","w",stdout);
    	fin>>N;
    	for(int i=1;i<=N;i++) fin>>a[i].w;
    	for(int i=1;i<=N;i++)
    	for(int j=1;j<=N+1;j++) F[i][j]=INF;
    	build();
    	dfs(st[1]);
    	for(int i=1;i<=N;i++) fout<<F[st[1]][i]<<'\n';
    	return 0;
    }
    
  • 相关阅读:
    Eleven-面向对象进阶
    Ten-面向对象
    Nine-常用模块
    Eight-内置函数和匿名函数
    Seven-递归函数和装饰器函数
    Six-迭代器和生成器
    Five-函数
    Four-深浅copy和文件操作
    Third-基础数据类型
    Second-基础
  • 原文地址:https://www.cnblogs.com/martian148/p/15563303.html
Copyright © 2011-2022 走看看