标签 - 贪心

构造 dp 贪心    2016-09-30 21:10:13    640    0    0

Description

Serpent(水蛇)生活的地方有N个水坑,编号为0,...,N - 1,有M条双向小路连接这些水坑。每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑之间根本无法互通(即M ≤ N-1 )。Serpent走过每条小路需要一个固定的天数,不同的小路需要的天数可能不同。Serpent的朋友袋鼠希望新修 N - M - 1条小路,让Serpent可以在任何两个水坑间游走。袋鼠可以在任意两个水坑之间修路,Serpent通过每条新路的时间都是L天。袋鼠希望找到一种修路方式使得修路之后Serpent在每两个水坑之间游走的最长时间最短。

举例说明

上图中有12个水坑8条小路( N = 12, M = 8)。假如L = 2 ,即Serpent通过任何一条新路都需要2天。那么,袋鼠可以修建3条新路: 
水坑1和水坑2之间;
水坑1和水坑6之间;
水坑4和水坑10之间。

上图显示了修路后的最终状态。从水坑0走到水坑11的时间最长,需要18天。这是 最佳结果,无论袋鼠如何选择修路方式,总会存在一些水坑对,Serpent需要18天 或者更长时间从其中一个走到另一个。
 

 

Input

N : 水坑的数目。
M : 原本存在的小路的数目。
L : Serpent通过新修的路经的时间。
A, B 和 T: 三个包含M个元素的数组,分别表示每条小路的两个端点和通过这条小路的时间。例如,第i条小路连接水坑 A[i-1]和水坑B[i-1],通过这条小路的时间是T[i-1]天。
 
 

Output


如上所述,表示游走于两个距离最远的水坑之间所需的时间。

Sample Input

12 8 2
0 8 4
8 2 2
2 7 4
5 11 3
5 1 7
1 3 1
1 9 5
10 6 3

Sample Output

18

HINT

 

 n <= 500000

 

Solution

贪心地构造解....

先求出每棵树i中与其他点的距离最大值最小的点的最大距离dis[i],然后把所有树接向dis最大的树...

至于求dis,我们可以维护节点u到子树的距离的最大值dp[u][0]和次大值dp[u][1].

若u是fa[u]的最大距离所在的子树,则dp[u][0] = max(dp[fa[u]][1] + w[fa->u], dp[v] + w[u->v])

否则dp[u][0] = max(dp[fa[u]][0

二进制 贪心    2016-09-27 13:58:15    211    0    0

Description

给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费用为c[1] or c[2] or ... or c[m]。请求出总费用的最小值。
 

 

Input

第一行包含两个正整数n,m(1<=m<=n<=500000),分别表示序列的长度和需要划分的段数。
第一行包含n个整数,其中第i个数为a[i](0<=a[i]<=10^18)。
 

 

Output

输出一个整数,即总费用的最小值。
 

 

Sample Input

3 2
1 5 7

Sample Output

3

HINT

第一段为[1],第二段为[5 7],总费用为(1) or (5 xor 7) = 1 or 2 = 3。

 

Solution

给定一个长度为n的序列,要求分成m段,使得每段异或和的或值最小 

看到异或和的最值问题,一般都可以想到贪心

求出前缀异或和后从大到小按位确定

如果某一位上有至少m个数是0且第n个数是0,那么这一位就可以是0,同时将所有是1的数字标记为不可选

 

#include <bits/stdc++.h>
#define ll long long
#define getchar getchar_unlocked
int n, m;
bool no[500005];
ll ans, s[500005];

inline ll read()
{
    static char c; ll x = 0;
    while (!isdigit(c = getchar())) ;
    for (; isdigit(c); c = getchar()) x = x * 10 + c - 48;
    return x;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++ i) {
        s[i] = read() ^ s[i - 1];
    }
    for (int K = 62; K >= 0; -- K) {
        if ((1ll << K) & s[n]) {
            ans |= 1ll << K;
            continue;
        }