2021icpc南京站

news/2024/10/18 0:31:32/

A.Oops, It’s Yesterday Twice More

题目链接:https://codeforces.com/gym/103470/problem/A

题意:给定一个n*n的方格,每个方格中可能会有袋鼠,你需要操作所有的袋鼠使得最后所有的袋鼠都能够到达(a,b),给出一种操作次数不超过3*(n-1)的操作方案。每次操作我们都会使得所有的袋鼠向一个方向移动,不能移动的袋鼠就不移动。ULDR为操作的命令

分析:我们首先需要将所有的袋鼠移动到同一个位置,然后再统一移动所有的袋鼠,我们可以将所有的袋鼠都移动到四个角落的某一个角落,具体移动到哪个角落取决于(a,b)距离哪个角落更近。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int main()
{int n,a,b;cin>>n>>a>>b;if(a<=n/2)//上半面 {if(b<=n/2)//左上{for(int i=1;i<n;i++)printf("LU");for(int i=1;i<a;i++)printf("D");for(int i=1;i<b;i++)printf("R");}else//右上 {for(int i=1;i<n;i++)printf("RU");for(int i=1;i<a;i++)printf("D");for(int i=1;i<=n-b;i++)printf("L");}}else//下半面 {if(b<=n/2)//左下 {for(int i=1;i<n;i++)printf("LD");for(int i=1;i<=n-a;i++)printf("U");for(int i=1;i<b;i++)printf("R");}else//右下 {for(int i=1;i<n;i++)printf("RD");for(int i=1;i<=n-a;i++)printf("U");for(int i=1;i<=n-b;i++)printf("L");}}return 0;
}

C. Klee in Solitary Confinement

题目链接:Problem - C - Codeforces

样例输入: 

9 -100
-1 -2 1 2 -1 -2 1 -2 1

样例输出:

3

题意:给你一个长度为n的数组和一个整数k,我们可以对数组进行操作,但是操作次数不得超过1,操作就是选择一个区间[l,r],把位于这个区间内的所有数都加上k,现在问我们操作后数组中出现次数最大的数的出现次数的最大值。

分析:对于每一个a[i]我们求一下他对a[i]+k产生的最大有效贡献即可。什么叫最大有效贡献呢?假如我们选定的区间中有p个a[i],q个a[i]+k,那么有效贡献就是p-q,这是比较容易理解的,因为操作后会多产生p-q个a[i]+k,所以我们只要遍历一下每一个a[i]即可,最后过程中记录一下最大值即可。关键是怎么求最大有效贡献呢?我们首先记录一下a[i]的出现位置并存入一个数组中,同理记录一下a[i]+k的出现位置并存入另一个数组中,对这两个数组进行从小到大排序,并设置两个指针分别指向两个数组的起始位置,然后每次选择一个靠前的位置,如果是a[i]靠前,那么我们就令贡献+1,否则令贡献-1,并移动相应的指针,如果贡献一旦减为负数,那么就令贡献为0,这个思想就是类似于最大子段和,最后在过程中记录一下每个a[i]的最大有效贡献即可。

需要特别注意的一点就是k=0的情况,这个时候直接取出现次数最大的数的出现次数作为答案即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=4e6+10;
vector<int>p[N];
vector<int>alls;
int main()
{int n,k;cin>>n>>k;int t;for(int i=1;i<=n;i++){scanf("%d",&t);p[t+2000001].push_back(i);alls.push_back(t+2000001);}sort(alls.begin(),alls.end());alls.erase(unique(alls.begin(),alls.end()),alls.end());int ans=0;for(int i=0;i<alls.size();i++){ans=max(ans,(int)p[alls[i]].size());if(k==0) continue; if(p[alls[i]+k].size()==0) continue;int f=0;//计算最多可以将多少个alls[i]变为alls[i]+k int nowf=0;//计算当前贡献 int l1=0,l2=0;int len1=p[alls[i]].size(),len2=p[alls[i]+k].size();while(l1<len1&&l2<len2){if(p[alls[i]][l1]<p[alls[i]+k][l2]){nowf++;f=max(f,nowf);l1++;}else{nowf--;if(nowf<0) nowf=0;l2++;}}if(l1!=len1){nowf+=len1-l1;f=max(f,nowf);}ans=max(ans,f+len2);}printf("%d",ans);return 0;
}

D.Paimon Sorting

题目链接:https://codeforces.com/gym/103470/problem/D

样例输入:

3
5
2 3 2 1 5
3
1 2 3
1
1

样例输出:

0 2 3 5 7
0 2 4
0

题意:给定一个长度为n的数组,然后给定一个排序代码,我们需要利用上述代码对原数组进行排序,问交换次数,输出是针对前k个元素排序的交换次数,输出k=1,2,……,n情况下的交换次数。

分析:先考虑对前k个元素进行排序的结果,对于i从1~k遍历,第i次遍历完的数组一定有前i个元素有序,那么我们下一次就是对第i+1个元素进行遍历交换,比如前i次排序后的结果是

2 5 8 8 9 6,其中i等于4,下一次对第5个位置进行排序,那么我们会先用6和8交换,然后再用8和9交换,得到2 5 6 8 8 9,交换次数是2,交换次数就是大于6的不重复的连续的元素个数,这个刚好可以用树状数组进行维护,所以对于固定前k个元素的情况我们可以O(klogk)解决,关键是我们怎么由k的答案得到k+1时的答案,因为我们加入第k+1个数时,这个时候我们需要对第k+1个数进行讨论,如果第k+1个数小于等于前k个数的最大值,那么我们可以知道在前k轮排序过程中是不会涉及到第k+1个数的,因为最大值之后的数是不可能发生交换的,那么只有在第k+1轮排序时才会对第k+1个数进行交换,那么他会交换多少次呢?因为第k+1次排序时前k个数已经有序了,这个时候在前k个数中有多少个不同且比第k+1个数大的数那么就会交换多少次,这个很容易讨论。关键是第k+1个数大于前k个数的最大值时我们需要多加思考一下,因为我们在对第一个数排序时,就会把第k+1个数放置在第一个位置,那么对于第一个位置的前k次排序时不会涉及到第k+1个数,但是当拿前k个数的最大值与第k+1个数比较时还会交换一次,所以会多交换一次,而且被交换到第k+1个位置上的数在对前k个数进行交换时不会再涉及到,这个时候我们可以把第k+1个数作为一个新的最大值进行考虑,并不影响中间过程的交换次数,但是当对第k+1个位置排序时还会涉及到一次,所以共涉及到2次,这是在前k个的最大值只出现一次的情况,如果前k次的最大值不只是出现一次,那么我们能够发现,由于原来前k个数中有多个最大值,而最大值与最大值是不会进行交换的,但是现在最大值变得更大了,因为最大值第一次出现的位置在一开始就挪至第k+1个数的位置了,那么从第二次出现最大值的位置往后,每个数都会多交换一次就是在遍历到这个位置的时候会多交换一次,这个答案我们必须要记录。这个地方需要找个数组仔细模拟一下。

细节见代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int a[N],c[N];
int lowbit(int x)
{return x&-x;
}
void add(int x)
{for(int i=x;i<N;i+=lowbit(i))c[i]++;
}
int sum(int x)
{int ans=0;for(int i=x;i;i-=lowbit(i))ans+=c[i];return ans;
}
int main()
{int T;cin>>T;while(T--){int n;scanf("%d",&n);for(int i=1;i<=n;i++) c[i]=0;for(int i=1;i<=n;i++)scanf("%d",&a[i]);long long ans=0;printf("%lld",ans);int mx=a[1];add(a[1]);int cnt=1;//记录当前树状数组中有多少个不重复元素 vector<int>p;//记录最大值出现的位置p.push_back(1);for(int i=2;i<=n;i++){if(a[i]<=mx){ans+=cnt-sum(a[i]);if(a[i]==mx)p.push_back(i);}else{if(p.size()==1)ans+=2;elseans+=2+i-p[1];mx=a[i];p.clear();p.push_back(i);}if(sum(a[i])-sum(a[i]-1)==0)add(a[i]),cnt++;printf(" %lld",ans);}puts("");}return 0;
}

H. Crystalfly

题目链接:Problem - H - Codeforces

样例输入: 

2
5
1 10 100 1000 10000
1 2 1 1 1
1 2
1 3
2 4
2 5
5
1 10 100 1000 10000
1 3 1 1 1
1 2
1 3
2 4
2 5

样例输出:

10101
10111

题意:给定一个有n个节点的有根树,根节点为1,每个节点i上有a[i]只苍蝇,还有一个对应的反应时间t[i],有个人一开始位于根节点,如果一旦人第一次到达i节点,那么i节点的所有子节点j上的苍蝇会在时间t[j]后飞走,人每到达一个节点,如果这个节点的苍蝇还没飞走就会把所有的苍蝇全部抓住,当反应时间还剩0s时人到达了,那么是人先抓苍蝇,问人最多能够抓到的苍蝇数目。

每个苍蝇的反应时间是小于等于3的。

分析:我们先来看一下这个3是干什么的。

以这个图为例,我们从1->2->1花费时间就是2s,那么我们下一秒从1->3需要花费1s, 那么总时间就是3s,也就是说我们对于每一个节点最多抓到他两个子节点上的苍蝇,前提还得是第二个节点的苍蝇的反应时间是3s,否则只能抓到一个节点的苍蝇。那么很显然如果1有更多的子节点,则其他子节点上的苍蝇都要飞走了,但其子节点的子节点上的苍蝇并不会受到影响,我们来看一下这样操作后对2号节点和3号节点的影响,因为我们是先到达了一次2节点,那么等我们返回1后,等下次再到2号节点时,会发现2号节点的所有子节点上的苍蝇都已经飞走了,而我们到达3号节点后我们就可以继续抓其子节点上的苍蝇。

树形DP含义:

f[i][0]代表第i个结点无贡献且其子节点苍蝇全部飞走的贡献 
f[i][1]代表第i个结点无贡献但其子节点全部未受干扰的贡献

那么答案就是a[1]+f[1][1].

如果当前节点的子节点中有反应时间为3s的子节点,那么我们就有可能存在上述情况,否则是不会存在上述回溯的过程的,如果不存在回溯的过程,我们直接选择一个子节点权值最大的点进行递归即可,否则我们需要找到上图中的2号点和3号点,对于除了这两个点之外的其他子节点j我们都是取f[j][1],因为我们还没有到达子节点j,那么j的子节点是不可能受到干扰的,而3号点由于是后到达的,那么我们要加上3号点的权值,也等价于3号点的子节点是不受到干扰的,因为刚开始干扰,而且下一秒我们就开始考虑3号点的子节点了,所以这里我们只需要多加一个3号点的点权即可。但是2号节点不一样,如果我们不访问2号节点的话,那么2号点的贡献是f[2][1],但是我们访问2号点之后2号点的贡献就是a[2]+f[2][0],所以新增的贡献就是a[2]+f[2][0]-f[2][1],我们只需要记录最大值次大值及其编号即可,而对于子节点反应时间为3s的节点我们也需要统计一下点权的最大值和次大值及其对应的编号即可,为什么都需要记录次大值呢?防止2号点和3号点的最大值对应的点是同一个,我们求出来的这两个贡献取一个加和最大值计入贡献即可。把最大贡献加入f[x][1]即可。

更新f[x][0]:因为x的所有子节点都已经飞走,那么我们什么时候到达其子节点意义不大,我们子需要取其子节点j中f[j][0]和f[j][1]的最大值即可。

更新f[x][1]:一开始默认所有的子节点j都取f[j][0]和f[j][1]的最大值即可,因为一开始也是默认子节点都不进入,我们只是最后选择两个节点来进行更新最优值,最后直接把新加的贡献计入f[x][1]即可。

细节见代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=2e5+10;
int h[N],e[N],ne[N],idx;
int a[N],t[N];
long long f[N][2];
vector<int> p[N];//p[i]记录第i个结点的子节点中时间等于3的结点 
//f[i][0]代表第i个结点无贡献且其子节点苍蝇全部飞走的贡献?
//f[i][1]代表第i个结点无贡献但其子节点全部未受干扰的贡献
int read()
{int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();return x*f;
} 
void add(int x,int y)
{e[idx]=y;ne[idx]=h[x];h[x]=idx++;
}
void dfs(int x,int fa)
{f[x][0]=f[x][1]=0;int mx1=0,id1=-1;//记录子节点为3s的节点的点权的最大值和对应的编号int mx2=0,id2=-1;//记录子节点为3s的节点的点权的次大值和对应的编号int mx3=0,id3=-1;//记录子节点的a[j]+f[j][0]-f[j][1]的最大值和对应的编号int mx4=0,id4=-1;//记录子节点的a[j]+f[j][0]-f[j][1]的次大值和对应的编号int mx=0;//记录子节点点权最大值
//	priority_queue<pair<long long,int> >q;for(int i=h[x];i!=-1;i=ne[i]){int j=e[i];if(j==fa) continue;dfs(j,x);if(t[j]==3){if(a[j]>mx1){mx2=mx1;id2=id1;mx1=a[j];id1=j;}else if(a[j]>mx2){mx2=a[j];id2=j;}}mx=max(mx,a[j]);if(a[j]+f[j][0]-f[j][1]>mx3){mx4=mx3;id4=id3;mx3=a[j]+f[j][0]-f[j][1];id3=j;} else if(a[j]+f[j][0]-f[j][1]>mx4){mx4=a[j]+f[j][0]-f[j][1];id4=j;}f[x][0]+=f[j][1];f[x][1]+=max(f[j][0],f[j][1]);}long long ans=f[x][1]+mx;if(id1!=-1)//代表子节点中有3s的{if(id3!=id1)ans=max(ans,f[x][1]+mx3+mx1);else{if(id2==-1)//3s的孩子结点只有一个 ans=max(ans,f[x][1]+mx4+mx1);elseans=max(ans,f[x][1]+max(mx1+mx4,mx2+mx3));}}f[x][1]=ans;
}
int main()
{int T;cin>>T;while(T--){idx=0;int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]),h[i]=-1;for(int i=1;i<=n;i++)scanf("%d",&t[i]);for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);add(u,v);add(v,u);}dfs(1,-1);printf("%lld\n",f[1][1]+a[1]);}return 0;
}

M. Windblume Festival

题目链接:Problem - M - Codeforces

样例输入: 

5
4
1 -3 2 -4
11
91 66 73 71 32 83 72 79 84 33 93
12
91 66 73 71 32 83 72 79 84 33 33 93
13
91 66 73 71 32 83 72 79 84 33 33 33 93
1
0

样例输出:

10
713
746
779
0

题意:给定一个长度为n的数组,你可以把这个数组看成是一个环形的,每次我们选择两个数进行合并,合并后的结果就是前一个数减去后一个数,问最后剩一个数时这个数最大能是多少。

分析:先假设我们最后剩余的数的位置是i,那么我们让第i个位置放在第一个位置,按照这个顺序对原数组进行一次重排,不妨设排序后的数组就是a[1~n]。

我们现在有a[1]  a[2]  ……  a[n]

我们现在就等价于在每一个位置前放一个符号,然后进行运算得到最后的结果就行。

那么每一个位置前面的正负号是随意的吗?答案是不完全是,除了前两个数之外的数的正负号可以随意加,因为第一个数前面必须是+,而第二个数前面必须是-,这是运算规则决定的,但是对于第i个数,如果我们想让其为+,那么我们可以先让其与第i-1个数进行一次操作,然后就变为了正号,最后直接从前往后依次选择相邻的两个数进行操作即可

比如我们现在想构造a[1]-a[2]-a[3]+a[4]+a[5]

那么我们从第2个数往后考虑,考虑前面是正号的数,那么发现第一个数是a[4],那么就先让他与前面一个数进行一次操作得到 a[1]  a[2]  a[3]-a[4] a[5]

发现a[5]前面也是正数,所以我们也让a[5]与其前面的数a[3]-a[4]进行一次操作得到a[1]  a[2]  a[3]-a[4]-a[5],剩下的都是负号了,我们直接从前往后依次选择两个数进行操作即可。

得到a[1]-a[2]-(a[3]-a[4] a[5])=a[1]-a[2]-a[3]+a[4]+a[5]

所以我们最后只需要选择两个相邻的数前一个取正号,后一个取负号,其余的数全部取绝对值即可,最后直接暴力枚举最大值即可

下面是代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
const int N=1e6+10;
int a[N];
int main()
{int T;cin>>T;while(T--){int n;scanf("%d",&n);long long s=0,ans=-0x3f3f3f3f3f3f3f3f;for(int i=1;i<=n;i++)scanf("%d",&a[i]),s+=abs(a[i]);if(n==1){printf("%d\n",a[1]);continue;}for(int i=1;i<=n;i++)ans=max(ans,s-abs(a[i])-abs(a[i%n+1])+(a[i]-a[i%n+1]));printf("%lld\n",ans);}return 0;
} 


http://www.ppmy.cn/news/534955.html

相关文章

疫情常态化,华为云会议不打烊

2022年初疫情再次袭来&#xff0c;多个大型城市开启了云上工作模式&#xff0c;据不完全统计&#xff0c;有三亿员工开启了居家办公、线上会议&#xff0c;12.6亿学生和2000万老师正在持续探索远程教学、会议直播、线上提交和批改作业的全新在线教学模式。华为云在云会议产品上…

保障出行安全|科力锐助力长沙黄花国际机场灾备建设

一、民航灾备建设背景 随着我国经济建设的发展&#xff0c;我国机场业已初具规模&#xff0c;机场数量不断提升&#xff0c;航班业务愈加繁忙&#xff0c;机场服务保证能力也在不断增强。为了衔接“空管全球一体化”的发展趋势&#xff0c;实现中国现代化民航系统的建设战略&a…

智慧机场解决方案-最新全套文件

智慧机场解决方案-最新全套文件 一、建设背景二、建设思路三、建设方案四、获取 - 智慧机场全套最新解决方案合集 一、建设背景 中国处在机场持续大规模建设过程中&#xff0c;政府也有意愿建设机场作为城市名片&#xff0c;经济持续增长会带来机场的持续建设&#xff1b;我国…

安科瑞无线测温产品在南京禄口国际机场项目的应用

摘要&#xff1a; 高压开关柜在运行过程中&#xff0c;柜内触点与母线连接处、动静触头电路发热过大&#xff0c;易引发停电和火灾事故。因此&#xff0c;高压开关柜内温度监测尤其是三相触点温度监测非常重要。高压设备存在裸露电压&#xff0c;传统的有线温度检测方法因无法完…

【初识 Docker | 中级篇】 Docker 安装 Redis

文章目录 前言一、安装 docker1、安装docker2、安装docker-compose 二、redis 单机安装1.创建配置文件1.1.创建目录1.2.创建redis.conf1.3.创建docker-compose.yml 2.启动redis容器 总结 前言 可以按照以下步骤在 Docker 中安装 Redis docker pull redis 拉取Redis镜像 docker…

诚邀莅临 | 天奥智能参展第86届中国国际医疗器械博览会

11月23-26日&#xff0c;第86届中国国际医疗器械博览会&#xff08;CMEF&#xff09;在深圳国际会展中心&#xff08;宝安新馆&#xff09;隆重举办。本届大会以“创新科技、智领未来”为主题&#xff0c;吸引了超过4000家国内外医疗器械、医用耗材、医疗机器人等企业参会。 南…

机场航站楼告别人工巡检,提高空间安全性

机场是现代化民航基础设施体系&#xff0c;加快数字化转型、建设更高水平的智慧城市已成为城市竞争的新赛道。图扑软件基于 HT 引擎为国内民航数字化转型支撑可视化服务提供有力的一环&#xff0c;融合物联网解决方案&#xff0c;打造适配场景的智慧机场三维可视化解决方案&…

国际海运出口的操作流程是怎样的?

国际海运运输因为方便快捷以及运费低等特点&#xff0c;一直以来是大多数外贸企业出口货物物流运输的首选&#xff0c;然而新进入外贸行业的朋友们&#xff0c;对于海运出口流程还不是很了解&#xff0c;今天箱讯小编就为大家来介绍下。 海运出口操作流程如下&#xff1a; 1、…