zoukankan      html  css  js  c++  java
  • 联赛模拟测试25 C. Repulsed 贪心+树形DP

    题目描述


    分析

    考虑自底向上贪心
    (f[x][k]) 表示 (x) 下面距离为 (k) 的需要灭火器的房间数,(g[x][k])
    表示 (x) 下面距离为 (k) 的多余灭火器数
    每个灭火器和房间的匹配在 (lca) 处处理
    每次假设子树里已经最优了,那么 (f[x][k]) 一定要用 (g[x][0])
    填满
    然后距离为 (k) 的一定会在 (x) 处匹配掉,否则到上面不会更
    优(可以交叉互换)
    在不存在距离为 (k) 的前提下,(k-1) 一定会在 (x) 处匹配掉否则
    可以交叉互换
    根处 (g)(f) 的匹配再做一个简单的贪心即可

    代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e5+5,maxk=22;
    int h[maxn],tot=1,n,s,k;
    struct asd{
    	int to,nxt;
    }b[maxn<<1];
    void ad(int aa,int bb){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    int f[maxn][maxk],g[maxn][maxk],siz[maxn],ans;
    void dfs(int now,int fa){
    	f[now][0]++;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==fa) continue;
    		dfs(u,now);
    		for(rg int j=0;j<k;j++){
    			f[now][j+1]+=f[u][j];
    			g[now][j+1]+=g[u][j];
    			if(g[now][j+1]>n) g[now][j+1]=n;
    		}
    	}
    	while(f[now][k] && g[now][0]<f[now][k]){
    		g[now][0]+=s;
    		ans++;
    	}
    	for(rg int i=0;i<=k;i++){
    		rg int cs=std::min(f[now][k-i],g[now][i]);
    		f[now][k-i]-=cs;
    		g[now][i]-=cs;
    	}
    	for(rg int i=0;i<k;i++){
    		rg int cs=std::min(f[now][k-i-1],g[now][i]);
    		f[now][k-i-1]-=cs;
    		g[now][i]-=cs;
    	}
    }
    int main(){			
    	memset(h,-1,sizeof(h));
    	n=read(),s=read(),k=read();
    	rg int aa,bb;
    	for(rg int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb);
    		ad(bb,aa);
    	}
    	dfs(1,0);
    	for(rg int i=0;i<=k;i++){
    		for(rg int j=k-i;j>=0;j--){
    			rg int cs=std::min(f[1][j],g[1][i]);
    			f[1][j]-=cs;
    			g[1][i]-=cs;
    		}
    	}
    	rg int nans=0;
    	for(rg int i=0;i<=k;i++){
    		nans+=f[1][i];
    	}
    	if(nans%s==0) ans+=nans/s;
    	else ans+=nans/s+1;
    	printf("%d
    ",ans);
    	return 0;	
    }
    
  • 相关阅读:
    连分数与丢番图方程简介
    利用 random 与 tertools 模块解决概率问题
    Notepad++ 几款实用插件简介,让你的 Notepad++ 如虎添翼
    .net面试问答(大汇总)
    .net反射详解 原文://http://blog.csdn.net/wenyan07/article/details/27882363
    ASP.NET MVC4+EF5(Lambda/Linq)读取数据
    AngularJS+ASP.NET MVC+SignalR实现消息推送
    Asp.net SignalR 实现服务端消息推送到Web端
    C# Socket编程 同步以及异步通信
    C#版 Socket编程(最简单的Socket通信功能)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13895763.html
Copyright © 2011-2022 走看看