zoukankan      html  css  js  c++  java
  • LUOGU P4253 [SCOI2015]小凸玩密室(树形dp)

    传送门

    解题思路

    玄学树形(dp),题目描述极其混乱。。。看错了两次题,设首先根据每次必须点完子树里的灯才能点别的,那么点灯情况只有两种,第一种是点到某一个祖先,第二种是点到某一个祖先的兄弟。所以可以设出状态(f[i][j][0/1])表示以(i)为根的子树已经点完,(0)表示下一步点到(j)祖先,(1)表示下一步点到(j)祖先的兄弟。然后转移的时候讨论一下这个点有几个儿子。最后算答案时枚举起点,然后一步一步往上跳,有兄弟的跳兄弟。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define int long long
    
    using namespace std;
    const int MAXN =200005;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    	while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    }
    
    int n,a[MAXN],f[MAXN][30][2],dis[MAXN][30],ans=1e18,ansN;
    
    inline int p(int i,int j){
    	return ((1<<(j-1))<=i)?(i>>j):-1;
    }
    
    inline int b(int i,int j){
    	return ((i>>(j-1))^1);
    }
    
    signed main(){
    	n=rd();dis[1][1]=0;
    	for(int i=1;i<=n;i++) a[i]=rd();
    	for(int i=2;i<=n;i++){
    		dis[i][1]=rd();
    		for(int j=2;~p(i,j);j++)
    			dis[i][j]=dis[p(i,1)][j-1]+dis[i][1];
    	}
    	for(int i=n;i;i--)
    		for(int j=1;~p(i,j);j++){
    		if((i<<1)>n) {
    			f[i][j][0]=dis[i][j]*a[p(i,j)];
    			f[i][j][1]=(dis[i][j]+dis[b(i,j)][1])*a[b(i,j)];
    			
    		}
    		else if((i<<1|1)>n){
    			f[i][j][0]=f[i<<1][j+1][0]+dis[i<<1][1]*a[i<<1];
    			f[i][j][1]=f[i<<1][j+1][1]+dis[i<<1][1]*a[i<<1];
    		}
    		else {
    			f[i][j][0]=min(f[i<<1][j+1][0]+f[i<<1|1][1][1]+dis[i<<1|1][1]*a[i<<1|1],
    						   f[i<<1|1][j+1][0]+f[i<<1][1][1]+dis[i<<1][1]*a[i<<1]);
    			f[i][j][1]=min(f[i<<1][j+1][1]+f[i<<1|1][1][1]+dis[i<<1|1][1]*a[i<<1|1],
    						   f[i<<1|1][j+1][1]+f[i<<1][1][1]+dis[i<<1][1]*a[i<<1]);
    		}
    	}
    	for(int i=1;i<=n;i++){
    		ansN=f[i][1][0];
    		for(int j=p(i,1),last=i;~j;j=p(j,1),last=p(last,1)){
    			if(b(last,1)<=n)
    				ansN+=dis[b(last,1)][1]*a[b(last,1)]+f[b(last,1)][2][0];
    			else 
    				ansN+=dis[j][1]*a[p(j,1)];	 
    		}
    		ans=min(ans,ansN);
    	}cout<<ans;
    	return 0;
    }
    
  • 相关阅读:
    Sybase:游标用法以及嵌套用法
    EasyUI:获取某个dategrid的所有行数据
    EasyUI:所有的图标
    Sybase:SAP IQ学习笔记
    Sybase:SybaseIQ的几个系统过程
    Sybase:解锁
    Python3:文件读写
    Android Studio 1.0.2 设置内存大小
    关于Android的margin(当前视图与周围视图的距离)和padding(当前视图与内部内容的距离)
    《Android Studio开发实战 从零基础到App上线》资源下载和内容勘误
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9805547.html
Copyright © 2011-2022 走看看