Codeforces Round #625 Div. 2
比赛链接 https://codeforces.com/contest/1321
比赛记录 https://blog.csdn.net/cheng__yu_/article/details/105395197
A. Contest for Robots
题意:设置每道题的分数让robo赢
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10,inf=2e9;
int n;
int a[maxn],b[maxn];
int main()
{
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=1;i<=n;++i) cin>>b[i];
int cnt1=0,cnt2=0;
for(int i=1;i<=n;++i)
if(a[i]==1&&b[i]==0) cnt1++;
else if(a[i]==0&&b[i]==1) cnt2++;
if(cnt1==0)
{
puts("-1");
return 0;
}
int ans;
if(cnt2%cnt1==0)
ans=cnt2/cnt1+1;
else
ans=ceil(cnt2*1.0/cnt1);
cout<<ans<<"\n";
return 0;
}
B. Journey Planning
题意:求满足
c
i
+
1
−
c
i
=
b
c
i
+
1
−
b
c
i
c_{i+1}-c_{i}=b_{c_{i+1}}-b_{c_i}
ci+1−ci=bci+1−bci的最大和
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+5,mod=1e9+7;
const int inf=0x3f3f3f3f;
ll n,a[maxn];
map<int,ll> m;
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
m[a[i]-i]+=a[i];
ll ans=0;
for(auto i :m)
ans=max(ans,i.second);
printf("%lld\n",ans);
return 0;
}
C. Remove Adjacent
题意:给定一个字符串 s 。对于一个字符 c ,如果相邻的字符比它小 1 ,那么就是可以移除的。问最多能够移除 s 中多少字符。
(
1
≤
∣
s
∣
≤
100
)
(1\le|s|\le 100)
(1≤∣s∣≤100)
思路:从 z 开始往 a 那边删。
- 方法一:每次先对字符串去重,把相同的叠在一起,然后删去。
- 方法二:每次删去一个字符之后,就重新从 z 开始删字符
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10,inf=2e9;
int n;
string s;
int counts[100];
int main()
{
cin>>n>>s;
int ans=0;
memset(counts,0,sizeof(counts));
vector<int> num(n,1);
for(int i=26;i>=1;--i)
{
n=s.size();
string tmp=s.substr(0,1);
int cnt=-1;
counts[++cnt]=num[0];
for(int i=1;i<n;++i)
if(s[i]==s[i-1]) counts[cnt]+=num[i];
else counts[++cnt]=num[i],tmp+=s[i];
num.clear();
char c='a'+i-1;
for(int j=cnt;j>=0;--j)
{
if(tmp[j]==c)
{
if(j+1<=cnt&&tmp[j+1]==c-1)
ans+=counts[j],tmp.erase(tmp.begin()+j),counts[j]=0;
else if(j-1>=0&&tmp[j-1]==c-1)
ans+=counts[j],tmp.erase(tmp.begin()+j),counts[j]=0;
}
}
for(int j=0;j<=cnt;++j)
if(counts[j]!=0)
num.push_back(counts[j]);
s=tmp;
}
cout<<ans<<"\n";
return 0;
}
D. Navigation System
题意:给定一张图,一个指定的路径,人会按照路径走。导航每次都会在一个新的点重新定位最短的路径。求导航最少导航几次,和导航最多导航几次
思路:
- 到达一个点的时候判断一下。如果当前边不在最短路上,mi++,mx++
- 如果当前边在最短路上,且存在两条最短路,mx++
实现:反向建图,从汇点开始跑dijstra。
- 假设从 u 走到 v。如果说dis[u]!=dis[v]+1,说明了边(u,v)并不在最短路上面,因此mi++,mx++
- 相反,如果说dis[u]=dis[v]+1,那么说明边(u,v)在最短路上面。此时找是否有两条以上的最短路。如果有mx++
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,inf=1e9;
int n,m;
vector<int> g1[maxn],g2[maxn];
int k,p[maxn],dis[maxn],visit[maxn];
void dijstra()
{
for(int i=1;i<=n;++i) dis[i]=inf;
dis[p[k]]=0;
priority_queue<pair<int,int> > pq;
pq.push({0,p[k]});
while(!pq.empty())
{
int u=pq.top().second;
pq.pop();
if(visit[u]) continue;
visit[u]=1;
for(auto v : g2[u])
{
if(dis[v]>dis[u]+1)
{
dis[v]=dis[u]+1;
pq.push({-dis[v],v});
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
g1[u].push_back(v);
g2[v].push_back(u);
}
scanf("%d",&k);
for(int i=1;i<=k;++i) scanf("%d",&p[i]);
dijstra();
int mi=0,mx=0;
for(int i=1;i<k;++i)
{
int u=p[i],v=p[i+1];
if(dis[u]!=dis[v]+1)
mi++,mx++;
else
{
for(auto t : g1[u])
if(dis[u]==dis[t]+1&&t!=v)
{
mx++;
break;
}
}
}
printf("%d %d\n",mi,mx);
return 0;
}
E. World of Darkraft: Battle for Azathoth
题意:n 件武器,第 i 件武器的攻击力为
a
i
a_i
ai,购买需要花费
c
a
i
ca_i
cai。m件防具,第 i 件防具的防御力为
b
i
b_i
bi,购买需要花费
c
b
i
cb_i
cbi。有 p 个怪兽,怪兽的防御力为
x
i
x_i
xi,攻击力为
y
i
y_i
yi,杀死怪物能够得到的金币为
z
i
z_i
zi。当武器的攻击力大于怪兽的防御力,并且防具的防御力大于怪兽的攻击力时,就可以杀死怪物,获得利益
z
z
z 。问至少购买一件武器和一件防具后,能够获得的最大利益是多少。
思路:首先可以明确只需要买一件武器和一件防具。然后,按照最暴力的方法想。第一维枚举武器,第二维枚举防具,第三维枚举怪兽,复杂度 O ( n 3 ) O(n^3) O(n3)。
- 怎样优化呢?我们让武器按攻击力从小到大排序。对于怪兽的防御力 x,那么所有大于防御力的武器,都可以杀死这只怪物。也就是这只怪物对这些武器都有贡献,那么就可以想到用线段树来更新贡献,维护利益的最大值。
- 将武器按攻击力从小到大排序,然后将花费更新到线段树上。枚举防具,对于攻击力(y)小于当前防具防御值的怪兽,对 [pos,n]的武器都存在贡献。更新后得到利益的最大值,再减去防具的花费,就是当前的答案。
- 可以发现这样的复杂度是 O ( m + p l o g n ) O(m+plogn) O(m+plogn)
#include <bits/stdc++.h>
#define fi first
#define se second
#define ls (rt<<1)
#define rs (rt<<1|1)
#define ll long long
using namespace std;
const int maxn=2e5+10,inf=1e9;
int n,m,p;
pair<int,int> a[maxn],b[maxn];
struct Monster
{
int x,y,z;
bool operator<(const Monster & b) const
{
return y<b.y;
}
}mo[maxn];
ll st[maxn<<2],lazy[maxn<<2];
void pushUp(int rt)
{
st[rt]=max(st[ls],st[rs]);
}
void pushDown(int rt)
{
if(lazy[rt])
{
st[ls]+=lazy[rt];
st[rs]+=lazy[rt];
lazy[ls]+=lazy[rt];
lazy[rs]+=lazy[rt];
lazy[rt]=0;
}
}
void build(int rt,int L,int R)
{
if(L==R)
{
st[rt]=-a[L].se;
return;
}
int mid=(L+R)>>1;
build(ls,L,mid);
build(rs,mid+1,R);
pushUp(rt);
}
void update(int rt,int l,int r,int L,int R,int val)
{
if(l<=L&&R<=r)
{
st[rt]+=val;
lazy[rt]+=val;
return;
}
pushDown(rt);
int mid=(L+R)>>1;
if(l<=mid)
update(ls,l,r,L,mid,val);
if(r>mid)
update(rs,l,r,mid+1,R,val);
pushUp(rt);
}
int main()
{
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;++i)
scanf("%d%d",&a[i].fi,&a[i].se);
for(int i=1;i<=m;++i)
scanf("%d%d",&b[i].fi,&b[i].se);
for(int i=1;i<=p;++i)
scanf("%d%d%d",&mo[i].x,&mo[i].y,&mo[i].z);
sort(a+1,a+1+n);
sort(b+1,b+1+m);
sort(mo+1,mo+1+p);
build(1,1,n);
ll ans=-4e18;
int now=1;
for(int i=1;i<=m;++i)
{
while(now<=p&&mo[now].y<b[i].fi)
{
int pos=upper_bound(a+1,a+1+n,make_pair(mo[now].x,inf))-a;
if(pos<=n) update(1,pos,n,1,n,mo[now].z);
now++;
}
ans=max(ans,st[1]-b[i].se);
}
printf("%lld\n",ans);
return 0;
}