Codeforces Round #786 (Div. 3)(E,G)

E. Breaking the Wall

题意:
n n n面连续的城墙,其都有自己的耐久 a i a_i ai,你的大炮可以攻击墙 i i i,使 a i − 2 , a i − 1 − 1 , a i + 1 − 1 a_i-2,a_{i-1}-1,a_{i+1}-1 ai2,ai11,ai+11,请问最少攻击多少次能最少破坏两堵墙
思路:
一共三种情况:
(1)破坏两面距离超过 2 2 2的墙 x , y x,y x,y,只要 ⌈ x 2 ⌉ + ⌈ y 2 ⌉ \left\lceil\dfrac{x}{2}\right\rceil+\left\lceil\dfrac{y}{2}\right\rceil 2x+2y
(2)破坏两面距离为 2 2 2的墙 x , y x,y x,y,由于无论怎样攻击都只会对整体造成 2 2 2的伤害,所以每次对两堵墙同时造成 1 1 1的伤害,打破一堵墙后开始对剩下的一面墙以此造成 2 2 2点伤害
(3)破坏两面相邻的墙 x , y x,y x,y,于是考虑分别对其攻击 p , q p,q p,q次,于是
{ 2 ∗ p + q ≥ x 2 ∗ q + p ≥ y ⟹ 3 ∗ ( p + q ) ≥ x + y \begin{cases}2*p+q\ge x\\2*q+p\ge y\end{cases} \Longrightarrow 3*(p+q)\ge x+y {2p+qx2q+py3p+qx+y
但是注意,答案并非 ⌈ x + y 3 ⌉ \left\lceil\dfrac{x+y}{3}\right\rceil 3x+y,还应该与最大的墙能承受的次数取最大值
例如 x = 11 , y = 1 x=11,y=1 x=11,y=1,答案为 6 6 6而非 4 4 4

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+7;
int a[maxn],c[maxn];
int cal(int x,int y)
{
	int ans=(x+y)/3;
	if((x+y)%3) ans++;
	ans=max(ans,(max(x,y)+1)/2);
	return ans;
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),c[i]=a[i];
	sort(c+1,c+1+n);
	int ans=(c[1]+1)/2+(c[2]+1)/2;
	for(int i=2;i<n;i++)
	{
		ans=min(ans,min(a[i-1],a[i+1])+(abs(a[i-1]-a[i+1])+1)/2);
	}
	for(int i=1;i<n;i++)
	{
		ans=min(ans,max((a[i]+a[i+1]+2)/3,(max(a[i],a[i+1])+1)/2));
	}
	printf("%d\n",ans);
}

G. Remove Directed Edges

题意:
给你有向无环图,要求你删除一些边,确保删完后,除了入度出度为 0 0 0的点不变,其余节点入度出度均下降,删完后留下的结点中,任意两点都有一条路径可以到达的节点有多大
思路:
由于图有向无环,所以所求的结点一定是一条链
所以在树上根据节点情况树形 d p dp dp即可

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef pair<int,int> PII;
const int maxn=2e5+7;
int n,m,in[maxn],out[maxn],f[maxn],vis[maxn];
vector<int>v[maxn];
void dfs(int u)
{
	vis[u]=1;
	f[u]=1;
	if(out[u]<=1)
	{
		return;
	}
	for(auto i:v[u])
	{
		if(vis[i]==0)
		dfs(i);
		if(in[i]>1) f[u]=max(f[u],f[i]+1);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		out[a]++;in[b]++;
		v[a].pb(b);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(vis[i]==0) dfs(i);
		ans=max(ans,f[i]);
	}
	printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值