zoukankan      html  css  js  c++  java
  • [2020.11.13]AGC035D

    题意

    给出一个长度为(n)的序列(A),每次可以做如下操作:

    任取一个整数(w),满足(2le wle)当前序列长度 ,令(A_{w-1})(A_{w+1})加上(A_w),然后删去(a_w)

    重复上述操作直到序列长度为(2),求最终(A_1+A_2)的最小值。

    题解

    不妨倒着考虑整个过程。每次考虑当前最后一个被删除的数并加入。

    (V_x)表示(A_x)向最终总和的贡献次数,一开始(V_1=V_n=1),那么设当(x)被加入时,它左边第一个已经被加入的数是(L),右边是(R),那么(V_x=V_L+V_R)

    于是,我们记(dp_{l,r,x,y})表示(l)(r)已经加入,([l+1,r-1])都还没加入,(V_l=x)(V_r=y) 时的最小贡献。

    那么

    [dp_{l,r,x,y}=min_{m=l+1}^{r-1}dp_{l,m,x,x+y}+dp_{m,r,x+y,y}+A_m imes(x+y) ]

    注意到状态中的(x,y)都是(O(2^n))级别,因此可以使用(map)和记忆化搜索实现。

    code:

    #include<bits/stdc++.h>
    #define ci const int&
    using namespace std;
    struct sta{
    	int l,r,x,y;
    	bool operator<(const sta&t)const{
    		return l==t.l?(r==t.r?(x==t.x?y<t.y:x<t.x):r<t.r):l<t.l;
    	}
    };
    int n,a[20];
    map<sta,long long>dp;
    long long DP(ci l,ci r,ci x,ci y){
    	if(l>=r-1)return 0;
    	if(dp.count((sta){l,r,x,y}))return dp[(sta){l,r,x,y}];
    	long long tmp=1e18;
    	for(int i=l+1;i<r;++i)tmp=min(tmp,DP(l,i,x,x+y)+DP(i,r,x+y,y)+1ll*a[i]*(x+y));
    	return dp[(sta){l,r,x,y}]=tmp;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
    	printf("%lld",DP(1,n,1,1)+a[1]+a[n]);
    	return 0;
    }
    
  • 相关阅读:
    【转载】ARM与单片机的区别
    关于头文件定义的一点思考
    关于*** WARNING L15: MULTIPLE CALL TO SEGMENT
    【转】单片机中volatile定义的作用详解
    关于单片机位数的思考(8位、16位、32位)
    memcpy函数
    ubuntu下打开windows里的txt文件乱码解决
    linux source filename
    linux环境设置export
    pdf转word工具
  • 原文地址:https://www.cnblogs.com/xryjr233/p/AGC035D.html
Copyright © 2011-2022 走看看