【2019.10.18】luogu TG5动态规划进阶

树形dp

P1352 没有上司的舞会

P2607 骑士(review)

对于每一个"联通快" 只有根节点有机会形成环

强制不选\(rt\)和\(rt\)的父亲 各跑一遍

P1131 时态同步(review)

贪心 显然增加深度约小的边越优

从下到上来调整 先将同一个点的儿子们延伸到一样 再往上进行一样的操作

//apio 烟火

树上背包?

一棵\(n\)个点的树,有点权。选择一个大小不超过\(K\)的联通块,使得点权和最大。\(n ≤ 2000\)

\(f(x, i)\)表示\(x\)的子树里选择\(i\)个点,并且\(x\)必须选的最大权值。 依次用\(x\)的每个儿子来更新\(f(x, ?)\)

枚举儿子\(y\),把\(g\)置为\(∞\)。

再枚举\(i, j\),用\(f(x, i) + f(y, j)\)更新\(g(i + j)\)。

然后用\(g(i)\)更新\(f(x, i)\)

重复直到所有儿子都被加入

可以看成每次把\(x\)的一个儿子合并到\(x\)上,并求出新的\(f(x, ?)\)。

用枚举点的子树大小限制枚举范围,复杂度\(O(n^2 )\)。

证明:每两个点都只会在最近公共祖先处被合并一次。

vector<int> G[N];
int f[N][N],g[N],siz[N];

void dfs(int x,int pa){
    siz[x]=1;
    for(auto y:G[x])if(y!=pa){
        dfs(y,x),siz[x]+=siz[y];
    }
    for(int i=0;i<=siz[x];i++)f[x][i]=INF;
    f[x][0]=0,f[x][1]=val[x];
    siz[x]=1;
    for(int i=0;i<G[x].size();i++){
        int y=G[x][i];
        for(int i=0;i<=siz[x]+siz[y];i++)g[i]=INF;
        for(int i=0;i<=siz[x];i++)for(int j=0;j<=siz[y];j++)
            g[i+j]=max(g[i+j],f[x][i]+f[y][j]);
        for(int i=0;i<=siz[x]+siz[y];i++)f[x][i]=max(f[x][i],g[i]);
        siz[x]+=siz[y];
    }
}

POI2017 Sabota

叛徒一定为一棵子树 第一个叛徒一定为叶子

\(v\)越小越容易变成叛徒 越大越不容易变成叛徒 找 使\(x\)变成叛徒的最小&最大\(v\)

最坏情况下,第一个叛徒一定是叶子,所以最终叛徒一定是一棵子树。

\(f(x)\)表示使得\(x\)不变成叛徒的最小的\(v\)

\(f(x)\)同时是使得\(x\)变成叛徒的最大的\(v\)

枚举叛变的子树,\(sizex\)表示\(x\)的子树大小

\[f(x)=max_{y\in son_x}\{min\{f(y),\frac{size_y}{size_x-1}\}\]

void dfs(int u){
    sz[u]=1,f[u]=0.0;
    for(int i=head[u],v;i;i=e[i].nxt) dfs((v=e[i].v)),sz[u]+=sz[v];
    for(int i=head[u],v;i;i=e[i].nxt)
        f[u]=Max(f[u],Min(f[v=e[i].v],(double)sz[v]/((double) sz[u]-1)));
    if(f[u]==0.0) f[u]=1.0;
    if(sz[u]>k) ans=Max(ans,f[u]);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    rd(n),rd(k);
    for(int i=2,u;i<=n;++i) rd(u),add(u,i);
    dfs(1);
    if(ans-0.0<1e-9) puts("0");
    else printf("%.10lf",ans);
    return 0;
}

COCI2009 podjela

一棵\(n\)个点的树,每个点上有一个农民。初始时每个农民有\(X\)的钱。 每一次操作,一个农民可以从它自己的钱中,取出任意数量的钱交给某 一个相邻的农民。对于每个农民给定一个值\(v_i\),问至少操作多少次,可以使得每个农民的钱\(≥\)给定的值

\(n ≤ 2000, X ≤ 10000\), 保证有解。

\(f(x, i)\)表示\(x\)的子树,进行操作后可以往上运/必须往下运\(i\)元,所需 的最小操作次数。\(O(nX^2 )\)

发现: 每一条边最多进行一次操作 总操作数不超过\(n ? 1\)

\(f(x, i)\)表示\(x\)的子树内部进行\(i\)次操作,根节点最多能给出多少钱。\(f(x, i)\)为负数表示还需要运进的钱数。 背包转移,每次把\(y\)加入\(x\)的子树中,并枚举\((x, y)\)这条边是否操作。

\(f(x, i) + f(y, j) → g(x, i + j + 1)\)

\(f(x, i) → g(x, i + j) (f(y, j) ≥ 0)\)总复杂度\(O(n^2 )\)

树上背包

int f[N][N],g[N],sz[N];
void dfs(int u,int ff){
    f[u][0]=K-a[u],sz[u]=1;
    for(int i=head[u],v;i;i=e[i].nxt)
    if((v=e[i].v)!=ff){
        dfs(v,u);
        for(int j=0;j<=sz[u]+sz[v];++j) g[j]=-inf;
        for(int j=0;j<sz[u];++j)
        for(int k=0;k<sz[v];++k){
            g[j+k+1]=Max(g[j+k+1],f[u][j]+f[v][k]);
            if(f[v][k]>=0) g[j+k]=Max(g[j+k],f[u][j]);
        }
        sz[u]+=sz[v];
        for(int j=0;j<=sz[u];++j) f[u][j]=g[j];
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    rd(n),rd(K);
    memset(f,~inf,sizeof(f));
    for(int i=1;i<=n;++i) rd(a[i]);
    for(int i=1,u,v;i<n;++i) rd(u),rd(v),add(u,v);
    dfs(1,0);
    printf("%d",lower_bound(f[1],f[1]+n,0)-f[1]);
    return 0;
}

P3479 灭火器

从下往上贪心,不得不配对的时候再配对。

\(f(x, i)\)表示\(x\)下面与\(x\)的距离为\(i\)的多余灭火器数量。

\(g(x, i)\)表示\(x\)下面与\(x\)的距离为\(i\)的需要灭火器的点数。

假设子树内最优,如果\(g(x, K) > 0\),那么需要在\(x\)处放灭火器,增加\(f(x, 0)\)进行匹配。

距离为\(K\)的两个点需要匹配,即 f(x, i) 覆盖掉 g(x, K ? i)。否则在上 面匹配不会更优。 距离为 K ? 1 的两个点也需要匹配,即 f(x, i) 覆盖掉 g(x, K ? i ? 1)。 否则无法在深度更小的点匹配。(距离变为 K + 1) 根节点特殊处理。

??? 我咕辽

状压dp

P1896 互不侵犯

P4163 排列

如果结果串为 T,我们要求出它对 d 取模的值。

记录值 val,从高到低扫描T的每一位\(T_i\),\(val = 10 × val + T_i\)

状压dp,f(S, i) 表示下标集合 S 内的数被用过了,当前的数模 d 为 i 的方案数

每次枚举一个不在 S 内的数加入 T 转移。

\(f(S, i) → f(S ∪ {k},(i × 10 + sk) mod d)\)最后答案是 $f({1, 2, · · · , n}, 0) $

int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
#endif
    int T;rd(T);
    while(T--){
        memset(f,0,sizeof(f));
        scanf("%s %d",s+1,&d);
        n=strlen(s+1);
        for(int i=1;i<=n;++i) a[i]=s[i]-'0';
        f[0][0]=1;
        for(int st=0;st<(1<<n)-1;++st){
            memset(vis,0,sizeof(vis));
            for(int i=1,nw;i<=n;++i)
            if(!(st&(1<<(i-1)))&&!vis[a[i]]){
                vis[a[i]]=1,nw=st|(1<<(i-1));
                for(int j=0;j<d;++j) f[nw][(j*10+a[i])%d]+=f[st][j];
            }
        }
        printf("%d\n",f[(1<<n)-1][0]);
    }
    return 0;
}

P2831 愤怒的小鸟(review)

两只小猪可以确定一条抛物线。

f(S) 表示消灭 S 内的小猪所需的最小小鸟数。枚举两只小猪转移。

预处理:s(i, j) 表示经过小猪 i 和 j 的抛物线会经过哪些猪。

转移:f(S) + 1 → f(S/s(i, j)) 复杂度:\(O(2^nn^2 )\)

优化:在 S 内任选一只猪,枚举另一只猪,而不需要枚举两只猪。 复杂度:$O(2^nn) $

P3959 宝藏(review)

树是一个分层结构,可以根据层数进行dp。

\(f(i, S)\)表示当前已经打通\(S\)内的点,树的最大深度为$i
$的最小代价。

预处理\(g(S, T)\)表示将\(T\)中所有点挂到\(S\)上的最小代价。 枚举下一层的点集\(T\)转移。

\(f(i, S) + g(S, T) × (i + 1) → f(i + 1, S ∪ T)\)

原来写的是记搜

#include <bits/stdc++.h>
#define FIO "race"
#define mset(a,b) memset(a,b,sizeof a)
#define mcpy(a,b) memcpy(a,b,sizeof b)
#define xx first
#define yy second
#define pb push_back
#define mp make_pair
#define pii pair<int,int>
#define lb(x) ((x)&(-(x)))
#define dalao 1000000007
#define inf 0x3f3f3f3f
#define M 4097
#define N 12
using namespace std;
typedef long long ll;
int n,m,S,T,a[N][N],f[2][M],g[M][M],mi,val,ans=inf;
int main(){
    scanf("%d%d",&n,&m);
    mset(a,0x3f);
    while(m--){
        int x,y,c;scanf("%d%d%d",&x,&y,&c),x--,y--;
        if(a[x][y]>c)a[x][y]=a[y][x]=c;
    }
    for(int i=0;i<n;i++)a[i][i]=0;
    for(int i=1;i<(1<<n);i++)for(int j=(i-1)&i;j;j=(j-1)&i){
        S=j,T=i^j;
        int tot=0;
        for(int x=0;x<n;x++)if(T>>x&1){
            mi=inf;
            for(int y=0;y<n;y++)if(S>>y&1)mi>a[x][y]?mi=a[x][y]:0;
            if(mi==inf){tot=50000000;break;}
            tot+=mi;
        }
        g[S][T]=tot;
    }
    for(int x=0;x<n;x++){
        mset(f,0x3f),f[0][1<<x]=0;
        for(int i=1,z=1;i<n;i++,z^=1){
            for(int j=1;j<(1<<n);j++)if(j>>x&1){
                f[z][j]=inf;
                for(int k=(j-1)&j;k;k=(k-1)&j)if(k>>x&1)
                    f[z][j]>(val=f[z^1][k]+g[k][k^j]*i)?f[z][j]=val:0;
            }
            ans>f[z][(1<<n)-1]?ans=f[z][(1<<n)-1]:0;
        }
    }
    printf("%d",ans);
    return 0;
}

S&T=0
\[
\Sigma_{i=0}^n2^iC_n^i =(2+1)^n =3^n
\]

P2157 学校食堂

f(i, j, S) 表示前 i ? 1 个人已经全部做好,第 i 个到第 i + 7 个人是否做 好的状态为 S,上一道菜是 j 的最少时间。 枚举下一个服务的人转移。 如果下一个人是 i,那么 f(i, j, S) + cost(j, i) → f(i + 1, i, S >> 1) 否则设为 k,f(i, j, S) + cost(j, k) → f(i, k, S ∪ {k ? i})

不想做,鸽掉!

for(int S=0;S<(1<<n);S++){
    for(int i=0;i<n;i++)for(int j=0;j<n;j++)if((S>>i&1)&&(S>>j&1))
        if(d[i][j]!=-1)val[S]+=d[i][j];
}

S&T=0

\[
\Sigma_{i=0}^n2^iC_n^i =(2+1)^n =3^n
\]

a|b-a&b=a xor b

0 0 0-0 = 0
0 1 1-0 = 1
1 1 1-1 = 0

AT 078F

?

数位dp

\(f(i,j,k,0,x)\rightarrow f(i+1,k,s,0,x|(s==k||s==j)) (0\le s\le 9)\)

\(f(i,j,k,1,x)\rightarrow f(i+1,k,s,[s=r_i],x|(s==k||s==j)) (0\le s\le R_i)\)

单调队列优化

P1725

未完==

原文地址:https://www.cnblogs.com/lxyyyy/p/11700579.html

时间: 2024-10-08 05:33:52

【2019.10.18】luogu TG5动态规划进阶的相关文章

2019.10.18考试解题报告

总结 期望得分:\(100 + 100 + 10\) 实际得分:\(0 + 20 + 10\) 完美. 今天的考试格外完美,\(T1\)做了*\(2.5h\),最后换来了\(0\)分的好成绩,史无前例,美妙绝伦,我竟然不删调试,做得?好. \(T2\)是个好题,是个好阅读题,\(n\)和\(m\)写反了,样例给的是\(n\)和\(m\)相等的情况,最终完美\(100->20\),我竟然这么粗心,题目竟然没读好,做得?好. \(T3\)没时间了,都耗在\(T1\)上了,可惜\(T1\)还没有分,做

2019.10.18模拟赛T3

题目大意: 求$\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)>n](n\leq 10^{10})$的值. 题解: 这题貌似有n多种做法... 为了更好统计,把原式变为$n^2-\sum\limits_{i=1}^n\sum\limits_{j=1}^n[lcm(i,j)\leq n]$. 然后开始毒瘤... 首先,考虑枚举$lcm(i,j)$,设为$d$,计算有多少对$i.j$的最小公倍数为$d$. 设$i=p_1^{a_1}p_2^{a_2}\

18. 蛤蟆的数据结构进阶十八排序实现之快速排序

18. 蛤蟆的数据结构进阶十八排序实现之快速排序 本篇名言:"一个人做点好事并不难,难的是一辈子做好事,不做坏事.--毛泽东" 我们最后来看下快速排序,以及各个排序之间的一些信息汇总. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47817933 1.  快速排序 快速排序由C. A. R.Hoare在1962年提出.它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分

2019.10.27 头条面试准备

2019.10.27 头条面试准备 个人简历 2019.06 - 至今上海华为开发工程师 实习部门:5G开发部 项目:网站开发.运维开发.数据处理 2019.06至今华为实习 Python+Django+Javascript+Nginx+rabbitMQ+ELK 基于 Django 框架使用 Python 开发网站基础进程监控系统,实现进程异常记录.进程异常自动恢复.发送告警邮件,并且用 Web 界面进行展示和管理.整个框架由本人独立设计完成并上线,保证了部门 Web 的稳定. 使用Python

10.15 iptables filter表案例 10.16/10.17/10.18 iptables nat表应用

10.15 iptables filter表案例 10.16/10.17/10.18 iptables nat表应用 扩展 iptables应用在一个网段 http://www.aminglinux.com/bbs/thread-177-1-1.html sant,dnat,masquerade http://www.aminglinux.com/bbs/thread-7255-1-1.html iptables限制syn速率 http://www.aminglinux.com/bbs/thre

6 10 18 32 下一个数?编程实现输入任意一个N位置,该数是多少?java实现

6 10 18 32 下一个数?编程实现输入任意一个N位置,该数是多少? 10 = 6 + 4         4 18 = 10 + 8        4 + 4 32 = 18 + 14       8 + 6 ? = 32 + 22       14 + 8 ? = 54 + 32       22 + 10 ? = 86 + 44       32 + 12 分析特点就是 f(x) = f(x-1)+ M; 其中M又是可递归的 4 8 14 22 f(N)=f(N-1)+2*N f(1)

10.15 iptables filter表小案例;10.16—10.18 iptables nat

扩展: 1. iptables应用在一个网段: http://www.aminglinux.com/bbs/thread-177-1-1.html 2. sant,dnat,masquerade: http://www.aminglinux.com/bbs/thread-7255-1-1.html 3. iptables限制syn速率: http://www.aminglinux.com/bbs/thread-985-1-1.html 10.15 iptables filter表小案例 ipta

10.15 iptables filter表案例 10.16/10.17/10.18 iptable

七周四次课 10.15 iptables filter表案例 10.16/10.17/10.18 iptables nat表应用 10.15 iptables filter表案例 10.16/10.17/10.18 iptables nat表应用 打开端口转发, 调整内核参数 增加一条规则 所添加的规则 B机器设置默认网关 设置公共DNS C设备与A通信,通过端口转换的形式,将原有iptables清空 上面为进来的包进行转换,下面为出去的包进行转换 原文地址:http://blog.51cto.

2019.3.18考试&amp;2019.3.19考试

2019.3.18 C O D E T1 树上直接贪心,环上for一遍贪心 T2 正反都做一遍DP T3 观察到顺序不影响答案,分块打标记 2019.3.19 肥肠爆芡,因为沙茶博主昨天在学校的煞笔食堂吃坏了肚子,所以这场考试咕咕了 我佛了 一定补这两场.jpg 原文地址:https://www.cnblogs.com/ydnhaha/p/10558495.html