【Virt.Contest】CF1321(div.2)
第一次打虚拟赛。
CF 传送门
T1:Contest for Robots
统计 \(r[i]=1\) 且 \(b[i]=0\) 的位数 \(t1\) 和 \(r[i]=0\) 且 \(b[i]=1\) 的位数 \(t2\)。
两个数都为 \(0\) 或都为 \(1\) 时没有贡献。
若 \(t1=0\),则 \(r\) 序列不管乘多大的 \(p\) 也不会比 \(b\)序列更大,所以直接输出 \(-1\)。
否则,我们考虑将 \(r[i]=0\) 且 \(b[i]=1\) 的位置的 \(p[i]\) 取 \(1\),总耗费 \(t2\),然后均摊到 \(r[i]=1\) 且 \(b[i]=0\) 的位数 \(t1\),显然最优。这时 \(p \max\) 即为 \(>\frac{t2}{t1}\) 的最小整数。
\(T1\) 还是比较水的,\(8min\) 切掉 \(qwq\)
Code:
#include<bits/stdc++.h>
using namespace std;
int n,a[105],b[105],T1,T2;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=n;i++){
if(a[i]==1&&b[i]==0) T1++;
if(b[i]==1&&a[i]==0) T2++;
}
if(T1==0) printf("-1");
else printf("%d",T2/T1+1);
return 0;
}
T2:Journey Planning
看到了 \(c_{i+1}-c_i=b_{c_{i+1}}-b_{c_i}\),对着样例想了一会才发现应该移项。变成:
\(b_{c_{i+1}}-c_{i+1}=b_{c_i}-c_i\)
由此发现,一次旅行所经过的点应该满足其美丽值与其下标的差相同。
所以想到用桶来存储差值。一开始脑抽,将要求 \(c_k>c_{k-1}\) 理解成了美丽值要递增,就想怎么还要分别做最大上升子序列,复杂度怎么都是不正确的。再看才发现是下标递增。这不直接把美丽值扔桶里算最大值就好了 \(qwq\)。
同时要注意,因为 \(b_{c_i}-c_i\) 可能为负值,不能直接做下标,所以将桶开大一些,以 \(n+b_{c_i}-c_i\) 做下标即可。
我才不会告诉你我没开 \(long\) \(long\) WA 了两发
较水,\(26min\) AC \(qwq\)
Code:
#include<bits/stdc++.h>
using namespace std;
long long n,a[200005],t[800005],ans;
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
int tmp=a[i]-i+n;
t[tmp]+=a[i];
ans=max(t[tmp],ans);
}
printf("%lld",ans);
return 0;
}
T3:Remove Adjacent
贪心。可以想到从 \(z\) 删到 \(a\) 是最优的。
思路很快就有了。让 \(k\) 从 \(z\) 开始,将字符串一位一位匹配,如果 \(s_i=k\),就往左右两边找,直到找到一个没有被删的,若其中一个是 \(k-1\),则可以删掉第 \(i\) 位,给它赋个随便啥字符就好(如 '#')。最后看有几个 '#',就是答案。于是,就有了下面的错误代码:
#include<bits/stdc++.h>
using namespace std;
string s,k="zyxwvutsrqponmlkjihgfedcba";
int ans,n;
int main(){
scanf("%d",&n);
cin>>s;
for(int i=0;i<=25;i++){
for(int j=0;j<n;j++){
if(s[j]!=k[i]) continue;
int l=max(j-1,0),r=min(j+1,n-1);
if(j!=0){
while(s[l]=='#'&&l>0) l--;
if(s[j]-1==s[l]) s[j]='#';
}
if(j!=n-1){
while(s[r]=='#'&&r<n-1) r++;
if(s[j]-1==s[r]) s[j]='#';
}
}
}
for(int i=0;i<n;i++) if(s[i]=='#') ans++;
printf("%d",ans);
return 0;
}
Then:
当时:test10 是个什么牛马*** 哪里出问题了呢?
于是手胡了几个数据,终于发现了错误:
10
yyyyxyyyyy
正确答案显然是 \(9\),因为所有 \(y\) 都可以被删掉。
但我的程序就输出 \(6\) 了。因为,对每个字母我只从左往右扫了一遍,所以前三个 \(y\) 被跳过之后就再也不管了 \(qwq\)。
所以,只要在每次删除后把 \(j\) 跳回 \(-1\) 就好了,从头再扫。由于 \(s\) 长度只有 \(100\) ,所以复杂度完全没问题。
最后,\(51min\) AC \(qwq\)
Code:
#include<bits/stdc++.h>
using namespace std;
string s,k="zyxwvutsrqponmlkjihgfedcba";
int ans,n;
int main(){
scanf("%d",&n);
cin>>s;
for(int i=0;i<=25;i++){
for(int j=0;j<n;j++){
if(s[j]!=k[i]) continue;
int l=max(j-1,0),r=min(j+1,n-1);
if(j!=0){
while(s[l]=='#'&&l>0) l--;
if(s[j]-1==s[l]) s[j]='#',j=-1;
}
if(j!=n-1){
while(s[r]=='#'&&r<n-1) r++;
if(s[j]-1==s[r]) s[j]='#',j=-1;
}
}
}
for(int i=0;i<n;i++) if(s[i]=='#') ans++;
printf("%d",ans);
return 0;
}
T4:Navigation System
看到最短路就懵。
一眼 \(Dijkstra\),但我还不会写板子。赛时套版固然不好,所以就先放着了,直接去看 \(T5\)、\(T6\)。然后也都没思路,就回来了。
思路:对于给出的路径 \(p\):
若当前所走到的 \(p_i\) 在唯一最短路,则不用变。
若当前所走到的 \(p_i\) 在最短路,但不唯一,则最多重构次数 \(+1\),因为导航可能给你导了另外一条最短路。
若当前所走到的 \(p_i\) 不在最短路,则最多重构次数、最少重构次数都 \(+1\),因为导航一定给你导了当前最短路,必须重置。
所以只要以终点 \(p_k\) 为起点,建一张反图,然后跑单源最短路即可。
看来要练最短路了
赛后代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,ans,ex,x,y;
int head[200005],rhead[200005],tot,rtot;
struct node{
int nxt,to;
}e[200005],re[200005];
int k,p[200005],t,s,dis[200005];
queue<int> q;
void add(int from,int to){
tot++;
e[tot].to=to;
e[tot].nxt=head[from];
head[from]=tot;
}
void radd(int from,int to){
rtot++;
re[rtot].to=to;
re[rtot].nxt=rhead[from];
rhead[from]=rtot;
}
void bfs(){
q.push(t);
memset(dis,0x3f,sizeof(dis));
dis[t]=0;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=rhead[u];i;i=re[i].nxt){
int v=re[i].to;
if(dis[v]==0x3f3f3f3f){
dis[v]=dis[u]+1;
q.push(v);
}
}
}
return ;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
add(x,y);
radd(y,x);
}
scanf("%d",&k);
for(int i=1;i<=k;++i) scanf("%d",&p[i]);
s=p[1],t=p[k];
bfs();
for(int i=1;i<k;i++){
int u=p[i];
if(dis[p[i+1]]+1!=dis[p[i]]) ans++;
else{
for(int j=head[u];j;j=e[j].nxt){
int v=e[j].to;
if(v==p[i+1]) continue;
if(dis[v]==dis[p[i+1]]){
ex++;
break;
}
}
}
}
printf("%d %d",ans,ans+ex);
return 0;
}
T5:World of Darkraft: Battle for Azathoth
首先,将武器按照攻击力从小到大排序,防具按照防御力从小到大排序,怪物按照防御力从小到大排序,然后将武器从左往右扫,可以知道武器 \(i\) 能打的怪物武器 \(i+1\) 也能打,所以能打的怪物个数是单调上升的。所以每次就将武器 \(i+1\) 比武器 \(i\) 多打的怪物加入集合中,然后维护防具 \(x\) 能在当前怪物集合中得到的利益。
显然对于能防御怪物 \(x\) 的防具连续的一段区间(因为排了序呀),于是就可以二分查找第一个严格大于怪物 \(x\) 的防御力的防具,然后区间加,再查找全局最大值就好了。
至于维护防具的数据结构,肯定线段树呀。
——来自 \(\color{red}{Silver187}\) 巨佬的 题解
记得线段树空间开 \(4\) 倍大!
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,p,k=1;
ll d[200005],ans=-1e16;
struct node1{ll x,y;}a[200005],b[200005];
struct node2{ll x,y,z;}c[200005];
struct tree{
int l,r;
ll dat,add;
}t[800005];
bool cmp1(node1 a,node1 b){return a.x<b.x;}
bool cmp2(node2 a,node2 b){return a.x<b.x;}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
t[p].dat=-b[l].y;
return ;
}
int md=(l+r)/2;
build(p*2,l,md);
build(p*2+1,md+1,r);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
void _updata(int p){
if(t[p].add){
t[p*2].add+=t[p].add;
t[p*2+1].add+=t[p].add;
t[p*2].dat+=t[p].add;
t[p*2+1].dat+=t[p].add;
t[p].add=0;
}
}
void _change(int p,int l,int r,ll d){
if(l<=t[p].l&&r>=t[p].r){
t[p].add+=d;
t[p].dat+=d;
return ;
}
_updata(p);
int md=(t[p].l+t[p].r)/2;
if(l<=md) _change(p*2,l,r,d);
if(r>md) _change(p*2+1,l,r,d);
t[p].dat=max(t[p*2].dat,t[p*2+1].dat);
}
ll q_max(int p,int l,int r){
if(l<=t[p].l&&r<=t[p].r) return t[p].dat;
_updata(p);
int md=(t[p].l+t[p].r)/2;
ll v=-1e16;
if(l<=md) v=max(v,q_max(p*2,l,r));
if(r>md) v=max(v,q_max(p*2+1,l,r));
return v;
}
void _add(int k){
int tmp=upper_bound(d+1,d+m+1,c[k].y)-d;
if(tmp<=m) _change(1,tmp,m,c[k].z);
}
int main(){
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
for(int i=1;i<=m;i++) scanf("%d%d",&b[i].x,&b[i].y);
for(int i=1;i<=p;i++) scanf("%d%d%d",&c[i].x,&c[i].y,&c[i].z);
sort(a+1,a+n+1,cmp1);
sort(b+1,b+m+1,cmp1);
sort(c+1,c+p+1,cmp2);
for(int i=1;i<=m;i++) d[i]=b[i].x;
build(1,1,m);
for(int i=1;i<=n;i++){
while(k<=p&&c[k].x<a[i].x) _add(k),k++;
ans=max(ans,q_max(1,1,m)-a[i].y);
}
printf("%lld",ans);
return 0;
}
T6:Reachable Strings
施工中 \(qwq\)