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
ai−2,ai−1−1,ai+1−1,请问最少攻击多少次能最少破坏两堵墙
思路:
一共三种情况:
(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
{2∗p+q≥x2∗q+p≥y⟹3∗(p+q)≥x+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);
}