"CSPS 2019 eleven" three exam

Because copyright reasons, face and hold the title.

happy

Solution

Only to write \ (70 \) points to find the law code, you can consider the contribution of each Fibonacci number of convolution, found that the contribution is similar to an inverted Fibonacci number, you can \ (O (n) \ ) done, there \ (70 \) points.

std is about simplifying the equation, the result is simplified

\[F_n = F_{n-1} + F_{n-2} + f_n\]

I found it to be a recursive formula, with matrix multiplication can be accelerated. But I do not matrix multiplication, the first cushions. Matrix multiplication can not get used to exit the recursive \ (70 \) points.

Code

#include <bits/stdc++.h>
using namespace std;
#define re register
#define F first
#define S second
typedef long long ll;
typedef pair<int, int> P;
const int N = 1e7 + 5, mod = 998244353;
const int INF = 0x3f3f3f3f;
int read() {
    int x = 0, f = 0; char ch = 0;
    while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return f ? -x : x;
}
ll fb[N], cnt[N]; 
ll ans = 0;
int main(){
    int n = read();
    fb[0] = fb[1] = 1;
    for (int i = 2; i <= n; i++) fb[i] = (fb[i - 1] + fb[i - 2]) % mod;
    cnt[n] = 1;
    for (int i = n - 1; i >= 0; i--) cnt[i] = (cnt[i + 1] + cnt[i + 2] + 1) % mod;
    ll ans = 0;
    for (int i = 0; i <= n; i++) ans = (ans + fb[i] * cnt[i]) % mod;
    printf("%lld\n", ans);
    return 0;
}

Tree chain split

Solution

Lca + tree can be used to convert all of the differential path for the right side, then we have to find the largest tree and the right side of the split chain. Because this is a tree without roots, so to commutation root dp, divided into two tree dp. But we can enumerate the root of violence, so there \ (65 \) points are sent.

With \ (F_i \) represents any point in the tree root to \ (I \) is the subtree rooted tree split chain. Can choose \ (1 \) for the root. This step can get a tree dp.

Consider how to change the root, provided \ (F_i \) is to \ (I \) is the chain split tree rooted tree. If the point \ (Y \) as the root, its father \ (X \) , he \ (X \) tree in the chain split sons \ (Z \) , from \ (1 \) start , down from the tree for DP, where \ (F_1 of F_1 = \) . Note that after changing the root to change the root but also to meet the son of each node only choose one, if \ (x \) tree split in the chain, \ (the y-\) is \ (x \) son, then change the root after the emergence of \ (x \) and \ (z \) is \ (y \) situation son, contrary to the requirements of the tree split chain, so we can only \ (x \) is connected to the \ ( Y \) changed to \ (X \) all connected to the sides after the \ (Y \) suboptimal side edges or not selected \ (Z \) , and the \ (X \)Optimal and suboptimal edge while adding \ (F_y \) in. If you do not have this problem, then select \ (x \) and \ (y \) the best edge can be. For Optimal side suboptimal while waiting just to be pre-connected to each point out all its sons, the largest right side and the right side of the big times in the first tree in dp.

All in all, a good topic tree.

Code

#include <bits/stdc++.h>
using namespace std;
#define re register
#define F first
#define S second
typedef long long ll;
typedef pair<int, int> P;
const int N = 1e6 + 5, M = 1e6 + 5;
const int INF = 0x3f3f3f3f;
int read() {
    int x = 0, f = 0; char ch = 0;
    while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return f ? -x : x;
}
struct edge{
    int to, nxt, cost;
}e[M];
int head[N], tot;
void addedge(int x, int y){
    e[++tot].to = y; e[tot].nxt = head[x]; head[x] = tot;
}
int dep[N], fa[N][30], lg[N];
ll f[N], F[N]; int mx1[N], mx2[N], val[N];
int n, m; ll sum, ans;
void dfs1(int x, int pre){
    dep[x] = dep[pre] + 1; fa[x][0] = pre;
    for (int i = 1; (1 << i) <= dep[x]; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for (int i = head[x]; i; i = e[i].nxt) if (e[i].to != pre) dfs1(e[i].to, x);
}
int lca(int x, int y){
    if (dep[x] < dep[y]) swap(x, y);
    while (dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
    if(x == y) return x;
    for (int k = lg[dep[x]] - 1; k >= 0; k--) if (fa[x][k] != fa[y][k]) x = fa[x][k], y = fa[y][k];
    return fa[x][0];
}
void dfs2(int x, int pre){
    for (int i = head[x]; i; i = e[i].nxt){
        int y = e[i].to;
        if (y != pre){
            dfs2(y, x); val[x] += val[y]; f[x] += f[y];
            if (mx1[x] <= val[y]) mx2[x] = mx1[x], mx1[x] = val[y]; 
            else if (mx2[x] <= val[y]) mx2[x] = val[y];
        }
    }
    f[x] += mx1[x];
}
void dfs3(int x, int pre){
    for (int i = head[x]; i; i = e[i].nxt){
        int y = e[i].to;
        if (mx1[x] <= val[x]) mx2[x] = mx1[x], mx1[x] = val[x];
        else if (mx2[x] <= val[x]) mx2[x] = val[x];
        if (y != pre){
            if (mx1[x] == val[y]) F[y] = F[x] - mx1[x] + mx2[x] - mx1[y] + max(mx1[x], mx1[y]);
            else F[y] = F[x] - mx1[y] + max(mx1[y], val[y]); 
            dfs3(y, x);
        }
    }
}
int main(){
    int n = read(), m = read();
    for (int i = 1; i <= n; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
    for (int i = 1; i < n; i++){
        int x = read(), y = read();
        addedge(x, y); addedge(y, x);
    }
    dfs1(1, 0);
    for (int i = 1; i <= m; i++){
        int x = read(), y = read();
        int k = lca(x, y);
        val[x]++, val[y]++, val[k] -= 2;
        sum += dep[x] + dep[y] - dep[k] * 2;
    }
    dfs2(1, 0); F[1] = f[1]; dfs3(1, 0);
    for (int i = 1; i <= n; i++) ans = max(ans, F[i]);  
    printf("%lld\n", sum - ans);
    return 0;
}

Small and small E F strikes again

Fucks like a dp, cuckoo.

Guess you like

Origin www.cnblogs.com/lyfoi/p/11616104.html