首页 > 其他分享 >CF440D 题解

CF440D 题解

时间:2024-07-25 21:41:18浏览次数:6  
标签:sz 连通 CF440D int 题解 复杂度 更新 dp

题面

注意到划分完这棵树以后,每条连通块之间的边的一端一定相同,且是大小为 \(k\) 的连通块。

于是考虑这个连通块的最高点,设 \(f(i,j)\) 为 \(i\) 点所在连通块大小为 \(j\) 时所需的最小边数。

令 \(f'(i)\) 为原来的 \(f(i)\)。

对于 \(i\) 的每个 \(s\in son(i)\),枚举从 \(s\) 来的连通块大小进行转移:

\(f(i,j)=\max_{w=0}^{\min(j-1,sz_s)}f(s,w)+f'(i,j-w)\)。

复杂度 \(O(n^3)\)。

初始值为 \(f(i,1)=0\)。

边界为 \(f(i,sz_i)=0,f(i,0)=1\)。(dp结束后赋值)

\(f(i,0)=1\) 是因为这个点的子树一定不会被选,先把和父亲的边算上,后面不需要特判。

考虑怎么求具体方案:设 \(g(i,j)\) 为 \(f(i,j)\) 的方案,每次更新 \(f(i,j)\) 后再更新 \(g(i,j)\)。

设 \(f(i,j)=f'(i,k)+f(s,j-k)\),则 \(g(i,j)=g'(i,k)+g(s,j-k)+[j=k](edge(i,s))\),\(g\) 的加法表示答案拼接,后面特判和子树断开要加边的情况。

\(g\) 更新 \(O(n^2)\) 次,每次 \(O(n)\),复杂度 \(O(n^3)\)。

于是直接 dp 就好了。注意树形 dp 时注意 \(sz\) 的更新,否则复杂度就错了。

总复杂度 \(O(n^3)\)。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 405;
int f[N][N], sz[N], k, ans = 1e9, idx;
vector<int> g[N][N];
int fst[N], nxt[N << 1], to[N << 1], h = 2, fid[N];
inline void add(int x, int y) {nxt[h] = fst[x], fst[x] = h, to[h] = y, h ++;}

void dfs(int x, int fa)
{
    f[x][1] = 0;
    sz[x] = 1;
    for(int e = fst[x], i = to[e]; e; e = nxt[e], i = to[e])
    {
        if(i == fa) continue;
        fid[i] = e / 2;
        dfs(i, x);
        sz[x] += sz[i];
        for(int j = sz[x]; j >= 0; j --)
        {
            int fnow = 1e9, id = -1;
            for(int k = 0; k <= min(j, sz[i]); k ++)
            {
                fnow = min(fnow, f[x][j - k] + f[i][k]);
                if(fnow == f[x][j - k] + f[i][k]) id = k;
            }
            g[x][j] = g[x][j - id];
            if(!id) g[x][j].push_back(e / 2);
            else g[x][j].insert(g[x][j].end(), g[i][id].begin(), g[i][id].end());
            f[x][j] = fnow;
        }
    }
    f[x][0] = 1;
    f[x][sz[x]] = 0;
    ans = min(ans, f[x][k] + !!fa);
    if(f[x][k] + !!fa == ans) idx = x;
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int n; cin >> n >> k;
    memset(f, 0x3f, sizeof f);
    for(int i = 1; i < n; i ++)
    {
        int x, y; cin >> x >> y;
        add(x, y);
        add(y, x);
    }
    dfs(1, 0);
    cout << ans << "\n";
    if(fid[idx]) g[idx][k].push_back(fid[idx]);
    sort(g[idx][k].begin(), g[idx][k].end());
    for(int i : g[idx][k]) cout << i << " ";

    return 0;
}

标签:sz,连通,CF440D,int,题解,复杂度,更新,dp
From: https://www.cnblogs.com/adam01/p/18324195

相关文章

  • CF56E 题解
    题面设骨牌\(i\)倒下之后会连带压倒\([i+1,r_i]\)的骨牌,那么有\(z_i=\max_{j=i+1}^{r_i}z_j+(j-i)\)考虑线段树优化dp,但是\((j-i)\)不好维护,所以套路地修改式子,得到:\(z_i+i=\max_{j=i+1}^{r_i}(z_j+j)\)所以线段树维护\(z_i+i\)的区间最大值即可,\(r_i\)可以二分求......
  • CF86D 题解
    题面看起来线段树之类的不好维护,但是移动区间的增量很好求,数据范围也能过,那么直接莫队就行了。设加入或删除了值\(x\),设原来区间内有\(cnt_x\)个,现在有\(cnt'_x\)个,那么增量就是\(x((cnt'_x)^2-(cnt_x)^2)\),直接求就好了。复杂度\(O(t\sqrtn)\)。#include<bits/stdc+......
  • CF567E 题解
    题面考虑如何一条边是必经之路:设\(cntl_i\)为从\(s\)到\(i\)走最短路的方案数,\(cntr_i\)为从\(i\)到\(t\)最短路方案数。由乘法原理,如果对于边\(e_i=(u,v)\),\(cnt_t=cnt_u\timescntr_v\),则\(e_i\)是最短路上的必经边,输出Yes即可。如果\(cnt_u\timescntr_v=0......
  • 【题解】Solution Set - 杂题选讲「刘君实」
    https://www.becoder.com.cn/contest/5423「HNOI2012」集合选数感觉差不多会。7/25sh杂题听课情况NOI2018冒泡排序【40】几乎不会麦田里的守望者【40】打表找规律、最后dp不太理解星空列车【40】完全不会WereYouLast:知道怎么做,但是不知道为什么是对的A......
  • CF467E 题解
    题面给出这种限制,我们只能4个4个考虑。令\(f_i\)为考虑到\(a_i\),最长的\(b\)序列长\(4f_i\)。令\(mx_i\)为以\(a_i\)结尾的最短连续子序列包含\(x\y\x\y\)的(不一定连续的)结构的左端点。于是有\(f_i=\max_{j=1}^{mx_i-1}f_j+4\)。用前缀和优化:\(g_i=\max......
  • CF594A 题解
    题面来个不一样的证明。根据样例,我们可以有一个直觉:两点之间一定距离\(\fracn2\),答案为这样的点对之间\(\Deltax\)的最小值。直接交上去,发现这是对的。为什么呢?先证明上界:先手可以让答案小于等于两点距离\(\fracn2\)点对的\(\Deltax\)的最小值。这是容易的:先手只......
  • 题解:Codeforces Round 961 (Div. 2) B1&B2
    本题含有B1和B2两个难度版本。由于关系相近,我把他们放在同一篇博客中,可自行选择观看B1.Bouquet(EasyVersion)timelimitpertest:1.5secondsmemorylimitpertest:512megabytesinput:standardinputoutput:standardoutputThisistheeasyversionoftheprobl......
  • CF568C New Language 题解
    Description将\(\texttt{a}\sim\texttt{a}+l-1\)这\(l\)个字符分成\(\texttt{V,C}\)两个集合。你需要构造一个长度为\(n\)且满足\(m\)个限制且不小于另一个长度为\(n\)的字符串\(s\)的最小字符串。每一个限制为若字符串的第\(p_1\)个位置上的字符\(\in......
  • CF22E 题解
    题面注意到题目给的图为基环树森林。因为一个(\(n>1\))的强连通图每个点都要有出度和入度,所以:对于每个基环树,叶子结点是没有入度的,所以一定要有一条从环上出发的路径经过这个点。对于基环树的环,注意到它缩点后没有出度,所以一定要有一条出边。注意到叶子结点的需求和根节点相反,......
  • 题解:AT_arc116_e [ARC116E] Spread of Information
    题目链接思路看到最大值最小首先可以想到二分,发现答案具有单调性,那么思考如何在\(O(n)\)的时间内判断是否合法。考虑贪心,在最远没覆盖的点的距离和要判断的\(mid\)刚好相等的时侯再选择一定不劣,因为这样覆盖的点最多,那么从叶子节点向上回溯,处理它的所有儿子,判断是否选择该......