noip2018

ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强ccj好强

D1T1

春春是一名道路工程师,负责铺设一条长度为 nnn 的道路。
铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 nnn 块首尾相连的区域,一开始,第 iii 块区域下陷的深度为 did_idi
春春每天可以选择一段连续区间 [L,R][L,R][L,R] ,填充这段区间中的每块区域,让其下陷深度减少 111。在选择区间时,需要保证,区间内的每块区域在填充前下陷深度均不为 000
春春希望你能帮他设计一种方案,可以在最短的时间内将整段道路的下陷深度都变为 000

题解

利用差分思想,用di−di−1d_i-d_{i-1}didi1得到新的序列aia_iai,然后ans=max(ai,0)ans=max(a_i,0)ans=max(ai,0)
效率 O(n)O(n)O(n)

D1T2

在网友的国度中共有 nnn 种不同面额的货币,第 iii 种货币的面额为 a[i]a[i]a[i],你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为 nnn、面额数组为 a[1..n]a[1..n]a[1..n] 的货币系统记作 (n,a)(n,a)(n,a)
在一个完善的货币系统中,每一个非负整数的金额 xxx 都应该可以被表示出,即对每一个非负整数 xxx,都存在 nnn 个非负整数 t[i]t[i]t[i] 满足 a[i]×t[i]a[i] \times t[i]a[i]×t[i] 的和为 xxx。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 xxx 不能被该货币系统表示出。例如在货币系统 n=3n=3n=3, a=[2,5,9]a=[2,5,9]a=[2,5,9] 中,金额 1,31,31,3 就无法被表示出来。
两个货币系统 (n,a)(n,a)(n,a)(m,b)(m,b)(m,b) 是等价的,当且仅当对于任意非负整数 xxx,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。
现在网友们打算简化一下货币系统。他们希望找到一个货币系统 (m,b)(m,b)(m,b),满足 (m,b)(m,b)(m,b) 与原来的货币系统 (n,a)(n,a)(n,a) 等价,且 mmm 尽可能的小。他们希望你来协助完成这个艰巨的任务:找到最小的 mmm

题解

显然 新的货币系统的 bib_ibi 的每个数都在原来的 aia_iai 中出现
证明一下?
如果说有新的数出现在 bib_ibi 中,那么它要么可以被原来的数表示,是不优的,要么不能被原来的数表示,是不符合条件的
所以问题转化成 aia_iai 中留下的数使得不留下的数都被留下的数表示,且最小化留下的数的个数
所以我们设 fjf_jfj 表示用 aia_iai 中的数组成 jjj 这个数的方案数
显然有 fj+=fj−aif_j+=f_{j-a_i}fj+=fjai
最后如果 fai=1f_{a_i}=1fai=1,那么它就只能被自身表示,故 ans++ans++ans++
效率 O(T×n×amax)O(T \times n \times a_{max})O(T×n×amax)

D1T3

C 城将要举办一系列的赛车比赛。在比赛前,需要在城内修建 mmm 条赛道。
C 城一共有 nnn 个路口,这些路口编号为 1,2,…,n1,2,…,n1,2,,n,有 n−1n-1n1 条适合于修建赛道的双向通行的道路,每条道路连接着两个路口。其中,第 iii 条道路连接的两个路口编号为 aia_iaibib_ibi,该道路的长度为 lil_ili 。借助这 n−1n-1n1 条道路,从任何一个路口出发都能到达其他所有的路口。
一条赛道是一组互不相同的道路 e1,e2,…,eke_1,e_2,…,e_ke1,e2,,ek ,满足可以从某个路口出发,依次经过道路 e1,e2,…,eke_1,e_2,…,e_ke1,e2,,ek (每条道路经过一次,不允许调头)到达另一个路口。一条赛道的长度等于经过的各道路的长度之和。为保证安全,要求每条道路至多被一条赛道经过。
目前赛道修建的方案尚未确定。你的任务是设计一种赛道修建的方案,使得修建的 mmm 条赛道中长度最小的赛道长度最大(即 mmm 条赛道中最短赛道的长度尽可能大)

题解

通过部分分可以大致推出正解算法
首先当 m=1m=1m=1 时,显然是树的直径最优
然后当 111 号点是根节点,可以利用贪心的思想,让一些边权大的边单独最为赛道,然后剩下的就小的和大的顺序匹配,取 minminmin 即为答案
当一条链时,显然可以二分答案
所以这题正解应该往二分+贪心想
首先我们二分答案 midmidmid,然后我们希望儿子传给父亲的边尽量大,所以我们可以把每个点得到的边权从小到大依次匹配到一条边,使得这两条边相加不小于 midmidmid,然后把剩余的最大的边往上传递即可,这里可以用 setsetset 维护边权
效率 O(n×logn×logr)O(n \times logn \times logr)O(n×logn×logr),其中 rrr 为二分的右端点

D2T1

YYY 是一个爱好旅行的 OIerOIerOIer。她来到X国,打算将各个城市都玩一遍。
YYY 了解到,XXX国的 nnn 个城市之间有 mmm 条双向道路。每条双向道路连接两个城市。不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且,从任意一个城市出发通过这些道路都可以到达任意一个其他城市。小 YYY 只能通过这些道路从一个城市前往另一个城市。
YYY 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该城市时经过的道路后退到上一个城市。当小 YYY 回到起点时,她可以选择结束这次旅行或继续旅行。需要注意的是,小 YYY 要求在旅行方案中,每个城市都被访问到。
为了让自己的旅行更有意义,小 YYY 决定在每到达一个新的城市(包括起点)时,将它的编号记录下来。她知道这样会形成一个长度为 nnn 的序列。她希望这个序列的字典序最小,你能帮帮她吗? 对于两个长度均为 nnn 的序列 AAABBB,当且仅当存在一个正整数 xxx 时,满足以下条件时,我们说序列 AAA 的字典序小于 BBB
对于任意正整数 1≤i&lt;x1≤i&lt;x1i<x,序列 AAA 的第 iii 个元素 AiA_iAi 和序列 BBB 的第 iii 个元素 BiB_iBi 相同。
序列 AAA 的第 xxx 个元素的值小于序列 BBB 的第 xxx 个元素的值。

题解

因为 m=n−1m=n-1m=n1m=nm=nm=n,所以我们可以分类一下
m=n−1m=n-1m=n1 时,我们直接从 111 号点 dfsdfsdfs 即可,然后每次编号小的先走即可
m=nm=nm=n 时,可以发现最后只有环上的一条边走不到,所以枚举删去环上的一条边,然后取最优的走法即可
效率 O(n2×logn)O(n^2 \times logn)O(n2×logn)

D2T2

DDD 特别喜欢玩游戏。这一天,他在玩一款填数游戏。
这个填数游戏的棋盘是一个 n×mn×mn×m 的矩形表格。玩家需要在表格的每个格子中填入一个数字(数字 000 或者数字 111 ),填数时需要满足一些限制。
下面我们来具体描述这些限制。
为了方便描述,我们先给出一些定义:
• 我们用每个格子的行列坐标来表示一个格子,即(行坐标,列坐标)。(注意:行列坐标均从 000 开始编号)
• 合法路径 PPP:一条路径是合法的当且仅当:

  1. 这条路径从矩形表格的左上角的格子 (0,0)(0,0)(0,0) 出发,到矩形的右下角格子 (n−1,m−1)(n−1,m−1)(n1,m1) 结束;
  2. 在这条路径中,每次只能从当前的格子移动到右边与它相邻的格子,或者从当前格子移动到下面与它相邻的格子。

对于一条合法的路径 PPP,我们可以用一个字符串 w(P)w(P)w(P) 来表示,该字符串的长度为 n+m−2n+m−2n+m2,其中只包含字符 &quot;R&quot;&quot;R&quot;"R" 或者字符 &quot;D&quot;&quot;D&quot;"D",第 iii 个字符记录了路径 PPP 中第 iii 步的移动方法,&quot;R&quot;&quot;R&quot;"R" 表示移动到当前格子右边与它相邻的格子,&quot;D&quot;&quot;D&quot;"D" 表示移动到当前格子下面与它相邻的格子。
同时,将每条合法路径 PPP 经过的每个格子上填入的数字依次连接后,会得到一个长度为 n+m−1n+m−1n+m1010101 字符串,记为 s(P)s(P)s(P)
游戏要求小 DDD 找到一种填数字 0、10、101 的方法,使得对于两条路径P1P1P1P2P2P2,如果 w(P1)&gt;w(P2)w(P1)&gt;w(P2)w(P1)>w(P2),那么必须 s(P1)≤s(P2)s(P1)≤s(P2)s(P1)s(P2)。我们说字符串 aaa 字符串 bbb,当且仅当字符串 aaa 的字典序小于字符串 bbb 的字典序,字典序的定义详见第一题。但是仅仅是找一种方法无法满足小 DDD 的好奇心,小 DDD 更想知道这个游戏有多少种玩法,也就是说,有多少种填数字的方法满足游戏的要求?
DDD 能力有限,希望你帮助他解决这个问题,即有多少种填 0、10、101 的方法能满足题目要求。由于答案可能很大,你需要输出答案对 109+710^9+7109+7 取模的结果。

题解

通过打表可以找出规律,然后就可以过了
效率 O(logm)O(logm)O(logm)

D2T3

ZZZ 国有 nnn 座城市, n−1n−1n1 条双向道路,每条双向道路连接两座城市,且任意两座城市都能通过若干条道路相互到达。
ZZZ 国的国防部长小 ZZZ 要在城市中驻扎军队。驻扎军队需要满足如下几个条件:
● 一座城市可以驻扎一支军队,也可以不驻扎军队。
● 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
● 在城市里驻扎军队会产生花费,在编号为 iii 的城市中驻扎军队的花费是 pip_ipi
ZZZ 很快就规划出了一种驻扎军队的方案,使总花费最小。但是国王又给小 ZZZ 提出了 mmm 个要求,每个要求规定了其中两座城市是否驻扎军队。小 ZZZ 需要针对每个要求逐一给出回答。具体而言,如果国王提出的第 jjj 个要求能够满足上述驻扎条件(不需要考虑第 jjj 个要求之外的其它要求),则需要给出在此要求前提下驻扎军队的最小开销。如果国王提出的第 j(1≤j≤m)j(1≤j≤m)j(1jm)个要求无法满足,则需要输出 −1−11。现在请你来帮助小 ZZZ

题解

似乎考场大家都会写 O(n×m)O(n \times m)O(n×m) 的暴力 dpdpdp ,只有我不会嘤嘤嘤
发现暴力不优秀的地方在于每次用 O(n)O(n)O(n) 的效率更新了所有的 dpdpdp 值,但是仔细想想有一些值是不用被更改的,所以我们要优化这一部分
g0/1,ig_{0/1,i}g0/1,i 表示选/不选第 iii 个点,在第 iii 棵子树内的最小代价
所以若没有限制,可以得到方程式
g0,i=∑g1,vg_{0,i}=\sum g_{1,v}g0,i=g1,v
g1,i=∑min(g0,v,g1,v)g_{1,i}=\sum min(g_{0,v},g_{1,v})g1,i=min(g0,v,g1,v)
对于一个询问 (x,y)(x,y)(x,y),我们可以一开始强制让不能出现的情况设为 INFINFINF ,然后我们发现我们会修改 ggg 的路径有 u−&gt;lcau-&gt;lcau>lcav−&gt;lcav-&gt;lcav>lcalca−&gt;rootlca-&gt;rootlca>root 这三条链,其他的子树的答案保持不变
考虑倍增预处理
f0/1,0/1,x,if_{0/1,0/1,x,i}f0/1,0/1,x,i 表示选/不选 xxx ,选/不选 xxx 向上走 2i2^i2i 步的祖先 yyy 时,从 x−&gt;yx-&gt;yx>y 的不包括 xxx 这个点的子树的答案(即 yyy 这个子树的答案扣除 xxx 这个子树的答案)
转移很简单
f0,0,x,0=INFf_{0,0,x,0}=INFf0,0,x,0=INF
f1,0,x,0=g0,fa0,x−g1,xf_{1,0,x,0}=g_{0,fa_{0,x}}-g_{1,x}f1,0,x,0=g0,fa0,xg1,x
f0,1,x,0=f1,1,x,0=g1,fa0,x−min(g0,x,g1,x)f_{0,1,x,0}=f_{1,1,x,0}=g_{1,fa_{0,x}}-min(g_{0,x},g_{1,x})f0,1,x,0=f1,1,x,0=g1,fa0,xmin(g0,x,g1,x)
fj,k,x,i=min(fj,0,x,i−1+f0,k,fai−1,x,i−1,fj,1,x,i−1+f1,k,fai−1,x,i−1)f_{j,k,x,i}=min(f_{j,0,x,i-1}+f_{0,k,fa_{i-1,x},i-1},f_{j,1,x,i-1}+f_{1,k,fa_{i-1,x},i-1})fj,k,x,i=min(fj,0,x,i1+f0,k,fai1,x,i1,fj,1,x,i1+f1,k,fai1,x,i1)
然后我们可以直接把 x,yx,yx,ylcalcalca 的路径上的 fff 数组加起来,并加上 xxx 的子树和 yyy 的子树的 ggg 值,再从 lcalcalca 开始加到根节点,就能算出总费用啦
问题来了,ggg 值都是包含当前我们在做的链下面的子树的贡献的,比如我们要用新的 xxxggg 值更新出新的 xxx 的父亲 fafafaggg 值时,要计算 fafafa 的别的子树的贡献,可是怎么处理出这一部分答案呢?
显然别的子树的答案是不会变的,而只有 xxx 这个子树的 ggg 值才会更改,所以我们可以先把这一部分在预处理时给 gfag_fagfa 的贡献值扣去,再加上新的值
所以我们可以得到
g0,fa+=new−g1,xg_{0,fa}+=new-g_{1,x}g0,fa+=newg1,x
g1,fa+=new−min(g0,x,g1,x)g_{1,fa}+=new-min(g_{0,x},g_{1,x})g1,fa+=newmin(g0,x,g1,x)
newnewnew 表示要新加的值
还有一些细节,具体看代码吧

#include <bits/stdc++.h>
#define F 2e18
#define I inline
#define LL long long
#define _(d) while(d(isdigit(c=getchar())))
using namespace std;
const int N=1e5+5;char typ[2];
I int R(){
    int x;bool f=1;char c;_(!) if (c==45) f=0;x=c^48;
    _() x=(x<<3)+(x<<1)+(c^48);return f?x:-x;
}
int n,m,head[N],V[N*2],nex[N*2],t,dep[N],fa[20][N],L;
LL g[2][N],f[2][2][20][N],a[N],X[2],Y[2],h[2],l[2],ans;
I void add(int u,int v){V[++t]=v;nex[t]=head[u];head[u]=t;}
void dfs1(int x){
    dep[x]=dep[fa[0][x]]+1;
    g[1][x]=a[x];f[0][0][0][x]=F;
    for (int i=1;fa[i-1][fa[i-1][x]];i++)
        fa[i][x]=fa[i-1][fa[i-1][x]];
    for (int i=head[x];i;i=nex[i]){
        if (V[i]==fa[0][x]) continue;
        fa[0][V[i]]=x;dfs1(V[i]);
        g[0][x]+=g[1][V[i]];
        g[1][x]+=min(g[0][V[i]],g[1][V[i]]);
    }
}
void dfs2(int x){
    f[1][0][0][x]=g[0][fa[0][x]]-g[1][x];
    f[0][1][0][x]=f[1][1][0][x]=g[1][fa[0][x]]-min(g[0][x],g[1][x]);
    for (int i=1;fa[i][x];i++) for (int j=0;j<2;j++) for (int k=0;k<2;k++)
        f[j][k][i][x]=min(f[j][0][i-1][x]+f[0][k][i-1][fa[i-1][x]],f[j][1][i-1][x]+f[1][k][i-1][fa[i-1][x]]);
    for (int i=head[x];i;i=nex[i]) if (V[i]!=fa[0][x]) dfs2(V[i]);
}
I void work(int x,int tx,int y,int ty){
    X[0]=X[1]=Y[0]=Y[1]=l[0]=l[1]=F;
    X[tx]=g[tx][x];Y[ty]=g[ty][y];
    int r=dep[x]-dep[y];
    for (int j=19;~j;j--) if ((1<<j)&r){
        h[0]=X[0];h[1]=X[1];
        X[0]=min(h[0]+f[0][0][j][x],h[1]+f[1][0][j][x]);
        X[1]=min(h[0]+f[0][1][j][x],h[1]+f[1][1][j][x]);
        x=fa[j][x];
    }
    if (x==y) L=y,l[ty]=X[ty];
    else{
        for (int j=19;~j;j--) if(fa[j][x]!=fa[j][y]){
            h[0]=X[0];h[1]=X[1];
            X[0]=min(h[0]+f[0][0][j][x],h[1]+f[1][0][j][x]);
            X[1]=min(h[0]+f[0][1][j][x],h[1]+f[1][1][j][x]);
            h[0]=Y[0];h[1]=Y[1];
            Y[0]=min(h[0]+f[0][0][j][y],h[1]+f[1][0][j][y]);
            Y[1]=min(h[0]+f[0][1][j][y],h[1]+f[1][1][j][y]);
            x=fa[j][x];y=fa[j][y];
        }
        L=fa[0][x];l[0]=g[0][L]-g[1][x]-g[1][y]+X[1]+Y[1];
        l[1]=g[1][L]-min(g[0][x],g[1][x])-min(g[0][y],g[1][y])+min(X[0],X[1])+min(Y[0],Y[1]);
    }
    if (L==1) ans=min(l[0],l[1]);
    else{
        r=dep[L]-2;
        for (int j=19;~j;j--) if((1<<j)&r){
            h[0]=l[0];h[1]=l[1];
            l[0]=min(h[0]+f[0][0][j][L],h[1]+f[1][0][j][L]);
            l[1]=min(h[0]+f[0][1][j][L],h[1]+f[1][1][j][L]);
            L=fa[j][L];
        }
        ans=min(g[0][1]-g[1][L]+l[1],g[1][1]-min(g[0][L],g[1][L])+min(l[0],l[1]));
    }
}
int main(){
    n=R();m=R();scanf("%s",typ);
    for (int i=1;i<=n;i++) a[i]=R();
    for (int x,y,i=1;i<n;i++)
        x=R(),y=R(),add(x,y),add(y,x);
    dfs1(1);dfs2(1);
    for (int x,tx,y,ty;m--;){
        x=R();tx=R();y=R();ty=R();
        if (dep[x]<dep[y]) swap(x,y),swap(tx,ty);
        work(x,tx,y,ty);printf("%lld\n",ans<F?ans:-1);
    }
    return 0;
}

转载于:https://www.cnblogs.com/xjqxjq/p/10544703.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值