Codeforces 1032F Vasya and Maximum Matching dp

Vasya and Maximum Matching

首先能观察出, 只有完美匹配的情况下方案数唯一。

dp[ i ][ 0 ], dp[ i ][ 1 ], dp[ i ][ 2 ] 分别表示

对于 i 这棵子树   0: 不向上连边完成  1:向上连边完成  2:向上连边未完成   的方案数

#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 3e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

int n;
vector<int> G[N];

LL power(LL a, LL b) {
    LL ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod; b >>= 1;
    }
    return ans;
}

LL dp[N][3];

void go(int u, int fa) {
    int pos = -1;
    for(int i = 0; i < SZ(G[u]); i++) {
        if(G[u][i] == fa) {
            pos = i;
            continue;
        }
        go(G[u][i], u);
    }
    if(~pos) {
        swap(G[u][pos], G[u][SZ(G[u]) - 1]);
        G[u].pop_back();
    }
}

void dfs(int u) {
    dp[u][0] = 1;
    dp[u][1] = 0;
    dp[u][2] = 1;
    if(!SZ(G[u])) return;
    for(auto& v : G[u]) dfs(v);
    int cnts = SZ(G[u]);
    vector<LL> prefix[3];
    for(int i = 0; i < 3; i++) {
        prefix[i].resize(cnts);
        for(int j = 0; j < cnts; j++) {
            int v = G[u][j];
            if(!j) prefix[i][j] = dp[v][i];
            else prefix[i][j] = prefix[i][j - 1] * dp[v][i] % mod;
        }
    }
    vector<LL> prefix01(cnts);
    vector<LL> suffix01(cnts);
    for(int i = 0; i < cnts; i++) {
        int v = G[u][i];
        if(!i) prefix01[i] = (dp[v][0] + dp[v][1]) % mod;
        else prefix01[i] = prefix01[i - 1] * (dp[v][0] + dp[v][1]) % mod;
    }
    for(int i = cnts - 1; i >= 0; i--) {
        int v = G[u][i];
        if(i == cnts - 1) suffix01[i] = (dp[v][0] + dp[v][1]) % mod;
        else suffix01[i] = suffix01[i + 1] * (dp[v][0] + dp[v][1]) % mod;
    }
// 0: 不向上连边完成  1:向上连边完成  2:向上连边未完成

    dp[u][0] = prefix[0][cnts - 1];
    for(int i = 0; i < cnts; i++) {
        int v = G[u][i];
        LL tmp = dp[v][2];
        if(i - 1 >= 0) tmp = tmp * prefix01[i - 1] % mod;
        if(i + 1 < cnts) tmp = tmp * suffix01[i + 1] % mod;
        add(dp[u][0], tmp);
        add(dp[u][1], tmp);
    }
    dp[u][2] = prefix01[cnts - 1];
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i < n; i++) {
        int u, v;
         scanf("%d%d", &u, &v);
         G[u].push_back(v);
         G[v].push_back(u);
    }
    go(1, 0);
    dfs(1);
    printf("%lld\n", dp[1][0]);
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/10820814.html

时间: 2024-10-29 14:49:39

Codeforces 1032F Vasya and Maximum Matching dp的相关文章

[Educational Round 59][Codeforces 1107G. Vasya and Maximum Profit]

咸鱼了好久...出来冒个泡_(:з」∠)_ 题目连接:1107G - Vasya and Maximum Profit 题目大意:给出\(n,a\)以及长度为\(n\)的数组\(c_i\)和长度为\(n\)的严格单调上升数组\(d_i\),求\(\max\limits_{1 \le l \le r \le n} (a\cdot(r-l+1)-\sum_{i=l}^{r}c_i-gap(l,r))\),其中\(gap(l, r) = \max\limits_{l \le i < r} (d_{i

Codeforces 354C Vasya and Beautiful Arrays[dp+暴力]

题意: 给出n个整数,对每个整数可以减去0-k的任意一个数 求这样操作后,n个数的最大GCD是多少 分析: 我们首先可以知道n个整数中最小的数是多少 而且,最终的答案肯定不大于这个数 这个n个整数中最小的数是答案的上限 然后对于答案的下限 可以肯定的是 1肯定是答案的下限 2呢?3呢?为什么1一定是 其实,0-k+1,都可以作为答案 为什么? 可以把k想象成一个剪刀 对k+1来说,任何数都可以剪掉0-k变成k+1的倍数(任何数模k+1的结果都是0-k) 所以0-k也可以,综上0-k+1都可以,所

Codeforces Round #261 (Div. 2) E (DP)

E. Pashmak and Graph Pashmak's homework is a problem about graphs. Although he always tries to do his homework completely, he can't solve this problem. As you know, he's really weak at graph theory; so try to help him in solving the problem. You are

Ural 1353 Milliard Vasya&#39;s Function(DP)

题目地址:Ural 1353 定义dp[i][j],表示当前位数为i位时,各位数和为j的个数. 对于第i位数来说,总可以看成在前i-1位后面加上一个0~9,所以状态转移方程就很容易出来了: dp[i][j]=dp[i][j]+dp[i][j-1]+dp[i][j-2]+.......+dp[i][j-9]: 最后统计即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <

CodeForces 540D Bad Luck Island 概率dp

CodeForces 540D 应该是简单概率dp,由于写得少显得十分蠢萌 求期望逆推,求概率正推,大概是这么个意思,贴一发留恋 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define db double const int maxn=108; db dp[maxn][maxn][maxn]; int main() { int i,j,n,m,k,p; whi

codeforces 148E Aragorn&#39;s Story 背包DP

Aragorn's Story Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/148/E Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

CodeForces 577C Vasya and Petya&#39;s Game 数学

题意就是给你一个1到n的范围 你每次可以问这个数是否可以被某一个数整除 问你要猜多少数才能确定这个数…… 一开始一点思路也没有 后来查了一下才知道 每个数都可以分为几个质数的整数次幂相乘得到…… 1 #include<stdio.h> 2 #include<iostream> 3 #include<algorithm> 4 #include<math.h> 5 #include<string.h> 6 #include<string>

CodeForces - 837E - Vasya&#39;s Function | Educational Codeforces Round 26

/* CodeForces - 837E - Vasya's Function [ 数论 ] | Educational Codeforces Round 26 题意: f(a, 0) = 0; f(a, b) = 1 + f(a, b-gcd(a, b)); 求 f(a, b) , a,b <= 1e12 分析: b 每次减 gcd(a, b) 等价于 b/gcd(a,b) 每次减 1 减到什么时候呢,就是 b/gcd(a,b)-k 后 不与 a 互质 可先将 a 质因数分解,b能除就除,不能