zoukankan      html  css  js  c++  java
  • CF1263F Economic Difficulties(DP)

    拿小号打了这场,然而做到这里时少看了条件,最后 10min 才发现,没有 AK,身败名裂……

    赛后看就是 sb 题……

    (好像这题也不值 2500 吧?)

    首先注意到一条很重要的条件:对于每棵树,都存在一种 DFS 序使得叶子被访问到的顺序就是与它相连的用电器的编号。

    这说明,对于每棵树的任意子树,里面所有叶子对应的用电器的编号是连续的。

    既然连续就能方便 DP 了。

    正着做不好设计状态。反过来,求最少能保留多少条边。

    那么就是每个用电器对应的叶子到根上的边都要选。没有限制的全部能删掉。

    然后由于用电器对应的叶子的 DFS 序递增,所以对于一个用电器集合 ({S}(|S|ge 2)),如果这里面每个用电器都和同一个根相连,那么 (S) 的花费 (cost_S)(cost_{S-x}+dep_x-dep_{lca(x,y)}),其中 (x)(S) 中编号最大的用电器,(y)(S) 中编号第二大的用电器。

    上 DP。

    先记 (f_{i,j,0}(i<j)) 表示第 (i) 个用电器和第 (j) 个用电器如果都选第 (0) 棵树时,(dep_{x_i}-dep_{lca(x_i,x_j)}) 的值。(f_{i,j,1}) 同理。

    再记 (fpre_{i,j,0}(ile j)) 表示第 (i) 个用电器到第 (j) 个用电器都选在第 (0) 棵树时的总花费。大概是个类似前缀和的东西。(fpre_{i,j,1}) 同理。

    再记 (dp_{i,j,0}(i>j)) 表示只考虑前 (i) 个用电器,第 (j) 到第 (i) 个用电器都选在第 (0) 棵树,且第 (j-1) 个用电器选在第 (1) 棵树的最小花费。(dp_{i,j,1}) 同理。

    转移,枚举第 (k) 到第 (j-1) 个用电器选在第 (1) 棵树(且 (k-1) 选在第 (0) 棵树)。(dp_{i,j,0}=fpre_{j,i,0}+min(dp_{j-1,k,1}+f_{k-1,j,0}-(dep_{x_j}[k e 1])))

    解释一下。

    (fpre_{j,i,0}) 就是 (j)(i) 的花费。

    (dp_{j-1,k,1}) 就是 (k)(j-1) 的最小花费。

    (f_{k-1,j,0}) 是因为:考虑从小到大加入 (j)(i),按上文说的最大编号和次大编号计算贡献。所以加入 (j) 时,就会比原来的花费多 (dep_{x_j}-dep_{lca(x_j,x_{k-1})}),也就是 (f_{k-1,j,0})

    (k e 1) 时,由于 (fpre) 中算的贡献中 (j) 是要自力更生的,但是实际上此时 (k-1) 可以给 (j) 一些已经用过的边(这个费用就是上面的 (f_{k-1,j,0}))。所以要把 (dep_{x_j}) 减掉。

    这是个 (O(n^3)) 做法。

    优化也很显然。设 (mn_{i,0}=min(dp_{i-1,j,1}+f_{j-1,i,0}-(dep_{x_i}[j e 1])))(mn_{i,1}) 同理。

    那么有 (dp_{i,j,0}=fpre_{j,i,0}+mn_{j,0})

    时间复杂度 (O(n^2))

    传说有 (O(n)) 做法,但我不会……

    代码中略微有一点不一样,稍微注意。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> PII;
    const int maxn=2222;
    #define MP make_pair
    #define PB push_back
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    #define ROF(i,a,b) for(int i=(a);i>=(b);i--)
    #define MEM(x,v) memset(x,v,sizeof(x))
    inline ll read(){
    	char ch=getchar();ll x=0,f=0;
    	while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f?-x:x;
    }
    int n,a,b,x[maxn],y[maxn],el,head[maxn],to[maxn],nxt[maxn],f[maxn][maxn][2],fpre[maxn][maxn][2],dp[maxn][maxn][2],mn[maxn][2];
    int fa[maxn],sz[maxn],son[maxn],dep[maxn],top[maxn];
    inline void add(int u,int v){
    	to[++el]=v;nxt[el]=head[u];head[u]=el;
    }
    void dfs1(int u,int f){
    	dep[u]=dep[fa[u]=f]+1;
    	sz[u]=1;
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		dfs1(v,u);
    		sz[u]+=sz[v];
    		if(sz[v]>sz[son[u]]) son[u]=v;
    	}
    }
    void dfs2(int u,int topf){
    	top[u]=topf;
    	if(son[u]) dfs2(son[u],topf);
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==son[u]) continue;
    		dfs2(v,v);
    	}
    }
    int lca(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]]) swap(u,v);
    		u=fa[top[u]];
    	}
    	return dep[u]<dep[v]?u:v; 
    }
    int main(){
    	n=read();
    	a=read();
    	FOR(i,2,a) add(read(),i);
    	dep[0]=-1;
    	dfs1(1,0);dfs2(1,1);
    	FOR(i,1,n) x[i]=read();
    	ROF(i,n,1){
    		int s=0;
    		FOR(j,i,n){
    			if(i==j) s=f[i][j][0]=dep[x[j]];
    			else s+=f[i][j][0]=dep[x[j]]-dep[lca(x[j],x[i])];
    			fpre[i][j][0]=fpre[i][j-1][0]+(i==j?f[j][j][0]:f[j-1][j][0]);
    		}
    	}
    	el=0;MEM(head,0);MEM(to,0);MEM(nxt,0);MEM(fa,0);MEM(sz,0);MEM(son,0);MEM(dep,0);MEM(top,0);
    	b=read();
    	FOR(i,2,b) add(read(),i);
    	dep[0]=-1;
    	dfs1(1,0);dfs2(1,1);
    	FOR(i,1,n) y[i]=read();
    	ROF(i,n,1){
    		int s=0;
    		FOR(j,i,n){
    			if(i==j) s=f[i][j][1]=dep[y[j]];
    			else s+=f[i][j][1]=dep[y[j]]-dep[lca(y[j],y[i])];
    			fpre[i][j][1]=fpre[i][j-1][1]+(i==j?f[j][j][1]:f[j-1][j][1]);
    		}
    	}
    	MEM(dp,0x3f);MEM(mn,0x3f);
    	dp[0][0][0]=dp[0][0][1]=mn[1][0]=mn[1][1]=0;
    	FOR(i,1,n) FOR(j,1,i){
    		dp[i][j][0]=fpre[j][i][0]+mn[j][1];
    		dp[i][j][1]=fpre[j][i][1]+mn[j][0];
    		if(i!=n){
    			mn[i+1][0]=min(mn[i+1][0],dp[i][j][0]+(j==1?0:f[j-1][i+1][1]-f[i+1][i+1][1]));
    			mn[i+1][1]=min(mn[i+1][1],dp[i][j][1]+(j==1?0:f[j-1][i+1][0]-f[i+1][i+1][0]));
    		}
    	}
    	int ans=1e9;
    	FOR(j,1,n) ans=min(ans,min(dp[n][j][0],dp[n][j][1]));
    	printf("%d
    ",a+b-2-ans);
    }
    
  • 相关阅读:
    unity远程修改游戏配置
    object与byte[]的相互转换、文件与byte数组相互转换
    c#实现gzip压缩解压缩算法:byte[]字节数组,文件,字符串,数据流的压缩解压缩
    Unity5.x在mac下的破解
    unity Socket TCP连接案例(一)
    Codeforces Edu Round 60 A-E
    Codeforces Edu Round 59 A-D
    Codeforces Edu Round 58 A-E
    Codeforces Edu Round 57 A-D
    Codeforces Edu Round 56 A-D
  • 原文地址:https://www.cnblogs.com/1000Suns/p/11962952.html
Copyright © 2011-2022 走看看