Codeforces Round 914 (Div. 2)补题

news/2024/12/29 17:19:46/

 Forked!(Problem - A - Codeforces)

题目大意:在棋盘中,我们指定骑士的运动方式——向一个方向运动a,然后向另一个方向运动b,两个方向必须是垂直关系。骑士此时能从一个点,进行两次这样的运动(两次运动都以同一个点为起点),且两次运动视为同时进行的,现在给出国王和王后的坐标,问骑士能否同时杀死国王和王后,另外棋盘无限大。

思路:我们这么想,骑士可以到的位置,那么那个位置同样可以以同样的方式到达骑士的位置,那么我们将国王和王后可以到的位置分别用set统计出来,再将两个set合并,最后的结果就是两个单set的size()-合并set的size().

#include<bits/stdc++.h>
using namespace std;
int dx[]={1,1,-1,-1};
int dy[]={1,-1,1,-1};
int main()
{int t;scanf("%d",&t);while(t--){int a,b;scanf("%d%d",&a,&b);int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);set<pair<int,int>>pa,pb,s;for(int i=0;i<4;i++){pa.insert({x1+dx[i]*a,y1+dy[i]*b});pb.insert({x2+dx[i]*a,y2+dy[i]*b});}for(int i=0;i<4;i++){pa.insert({x1+dx[i]*b,y1+dy[i]*a});pb.insert({x2+dx[i]*b,y2+dy[i]*a});}for(auto i:pa) s.insert(i);for(auto i:pb) s.insert(i);int ans=pa.size()+pb.size()-s.size();printf("%d\n",ans);}
}

Collecting Game(Problem - B - Codeforces)

题目大意:现有一个数组a[],我们从中选一个数作为初始分数,并将这个数拿出来,然后我们去这个数组中进行操作,如果某个数小于等于当前分数,那么我们将当前分数加上这个数得到新的分数,并将这个数移出数组,我们最后需要输出,以每个数为初始位置的时候,能得到的最终分数。

思路:我们考虑,一个数被选后,小于等于它的数肯定也能被选,大于它的数就要看看它和小于它的数的和是否大于它,所以实际上就是排序算前缀和,我们定义s[i]为位置i处的前缀和。那么能选多少个数该怎么确定呢。我们知道对于数组中最大的数,它能选的数就是n-1,那么对于第二大的数,如果s[i]>=a[i+1](假设第i个是第二大的数,i+1是最大的数),那么a[i+1]能选的数,它也一定可以选了,如果s[i]<a[i+1],那么它就只能选它前面的即i-1个(我们的a[]是排好序的)。至此就是一个简单的动态规划了。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[100010],b[100010],s[100010];
signed main()
{int t;scanf("%lld",&t);while(t--){int n;scanf("%lld",&n);for(int i=1;i<=n;i++) scanf("%lld",&a[i]),b[i]=a[i];sort(a+1,a+1+n);s[1]=a[1];map<int,int>mp;for(int i=2;i<=n;i++) s[i]=s[i-1]+a[i];mp[a[n]]=n-1;for(int i=n-1;i>=1;i--){if(s[i]>=a[i+1]) mp[a[i]]=mp[a[i+1]];else mp[a[i]]=i-1;}for(int i=1;i<=n;i++) printf("%lld ",mp[b[i]]);printf("\n");}
}

Array Game(Problem - C - Codeforces)

 题目大意:现有一个大小为n的数组a[],我们每次操作可以任意挑两个数,将它们差的绝对值加进数组,问k次操作后,a[]中的最小值是什么。

思路:我们可以发现,结果很明显与k有关系,如果k=1,那么实际上,我们只能执行一次操作,结果的一定是原数组中的最小值或者某两个数的差;如果k=2,我们只能执行两次,首先执行一次可以得到一个新数,然后一次操作,我们可以选择一个原数和这个新数进行计算,不然意义不大,所以最小值有三个来源,原数组中的数,新产生的这个数,新产生的这个数和原数组中某个数的差值;k=3,这是我最生气的一点,真没想到这种情况没有分析清楚,这个实际上是最简单的一种情况,我们对于两个数a,b,第一次操作得到c=b-a,第二次操作d=b-c=b-b+a=a,第三次操作d-a=0,所以这种情况是恒为0的。真离谱,这么简单的情况竟然没分析清楚。所以还是要考虑到这道题的k到1e9了,所以就要想一想,是否k大于等于某个值后,情况都一样,因为这里很明显不能暴力求解,那么就可以从这个角度找找规律。然后就没什么说的了,就是涉及到操作数的,而且操作数很大的就要考虑下这里的操作实际有效的是哪些(或者是哪些组合)(上次的这个题就是,实际有效的操作仅仅5个)或者考虑一下当操作数为多少之后,后面的情况都和它一样。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[2010];
signed main()
{int t;scanf("%lld",&t);while(t--){int n,k;scanf("%lld%lld",&n,&k);int mi=2e18;for(int i=1;i<=n;i++) scanf("%lld",&a[i]),mi=min(mi,a[i]);if(k>=3) printf("0\n");else{sort(a+1,a+1+n);for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){int tmp=a[j]-a[i];mi=min(mi,tmp);if(k==2){int p=lower_bound(a+1,a+1+n,tmp)-a;mi=min(mi,tmp-a[p-1]);mi=min(mi,a[p]-tmp);}}}printf("%lld\n",mi);}}
}

Set To Max (Easy Version)(Problem - D1 - Codeforces)

题目大意:我们给定两个长度均为n的数组a[]和b[],我们可以进行的操作是,从a[]中选一段区间[l,r],将这段区间内的a[i]全部改成这段区间的最大值,问最后能否使a[]变成b[].

思路:我们来考虑,对于某处的a[i],我们需要将它修改成b[i],那么一定要在它的前面或者后面找一个a[j],使得a[j]==b[i],所以我们就分两种情况来讨论,一种是在前面找,一种是在后面找(等价于将数组倒序,再从前往后找一遍),那么我们现在就来看从前面找如何实现。

首先,ak...aj...ai...,如果此时ak==aj==bi,那么区间ak和aj都是可以的,但是我们选aj的话可以减少对[k,j]这一段的影响,因为这段的影响本来就是可以避免的。然后我们再来看,如果aj可以去修改ai需要满足什么条件,首先aj需要是区间[j,i]中的最大值,其次我们一旦修改那么[j,i]的范围内的所有a就都变成aj了,后面只能变大,不能再变小了,所以这一段中的b必须大于等于aj,否则就不能成立。我们对于每一个i都要去找一个aj,但是如果真的去判断这两个条件是否成立的话,显然是超时的。所以我们要用别的方法来代替。

对于条件1,aj是[j,i]中的最大值,那么我们如果对于每个aj都能知道它往后最远能修改到哪里,然后判断一下i是否在他能修改的位置内,不就可以实现了吗;对于第二个条件,中间那段b必须大于等于aj,那么我们可以从ai往前找,找到小于aj(bi)的位置,然后标记一下,然后我们判断一下j是否在这个位置之前不就可以了,如果不在这个位置之前,那么不就可以修改。所以现在很明显,我们需要预处理两个数组出来,我们看看这两个数组的预处理如何实现。

对于第一个预处理数组,我们需要找到每一个位置j,a[j]后面第一个大于它的数,因为小于等于它的话实际上都可以被它修改。那么该如何找呢,对于每一个位置暴力肯定不可以,upper_bound()也不行,因为数组并非有序的,那么这里的解决思路是从后往前访问,用栈(或是说滑动窗口的思想)来优化。我们可以发现,我们将后面的数入栈,访问到aj的时候,如果栈中有一些小于等于它的数,那么再往前,如果访问到小于aj的数,那么找到的位置是j,如果大于等于aj,那么找到的位置肯定也不会在这些小于等于aj的数中,那么实际上,我们可以将这些数弹出去,因为后面一定不会再用到它们。这样的话,实际上就实现了优化,我们抛弃了冗余的访问。

对于第二个预处理数组,我们需要找到每一个位置i,b[i]前面第一个小于它的数,因为如果我们的j在小于b[i]的数前面的话,那么修改的时候,会将一些a[k]变大,大过b[k]而且无法改回去。所以我们就要找到j往左最远能到哪里,一旦j超过这个最左的范围,就不能用来修改了。那么我们就来看,如何找到前面第一个小于b[i]的数,暴力肯定是不行的,二分也不行,因为数组无序,那么这里也是用栈(滑动窗口的思想来优化的)。我们从前往后访问,将数放入栈中,对于b[i],如果栈中有一些大于等于它的数,那么再往后,如果访问到的数大于b[i],那么找到的位置就是i,如果访问到的数小于等于b[i],那么找到的位置肯定也不会在这一片大于等于b[i]的数中,所以这部分是冗余的,我们需要将它们弹出,减少无效访问。

至此两个预处理数组都解决了,现在只用去遍历a[i]并不断更新位置数组(用来记录上个值为b[i]的数出现的位置),然后对于每一个a[i]<b[i](大于的话肯定不可以)获取上一次b[i]出现的位置j,并判断这个位置j是否满足上面的两个条件如果满足,那么就可以用来修改。然后再将数组转置,按照同样的步骤处理一遍,对于每一个位置,我们用一个数组来标记是否找到,然后遍历,如果正反序都没找到的话,那么直接判否,否则就可以判是。

#include<bits/stdc++.h>
using namespace std;
int a[2010],b[2010],la[2010],pr[2010],v[2010],pos[2010];
signed main()
{int t;scanf("%d",&t);while(t--){int n;scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]),v[i]=0;for(int i=1;i<=n;i++) scanf("%d",&b[i]);for(int z=0;z<2;z++){stack<pair<int,int>>p;p.push({2000,n+1});for(int i=n;i>=1;i--){while(p.top().first<=a[i]) p.pop();//找后面第一个大于a[i]的位置la[i]=p.top().second;p.push({a[i],i});}while(p.size()) p.pop();p.push({0,0});for(int i=1;i<=n;i++){while(p.top().first>=b[i]) p.pop();//找前面第一个小于b[i]的位置pr[i]=p.top().second;p.push({b[i],i});}memset(pos,0,sizeof pos);for(int i=1;i<=n;i++){pos[a[i]]=i;if(a[i]==b[i]) v[i]=1;if(a[i]<b[i]&&pos[b[i]]){if(pos[b[i]]>pr[i]&&la[pos[b[i]]]>i) v[i]=1;}}reverse(a+1,a+1+n);reverse(b+1,b+1+n);reverse(v+1,v+1+n);}int flag=1;for(int i=1;i<=n;i++){if(!v[i]){flag=0;break;}}if(flag) printf("YES\n");else printf("NO\n");}
}

ps:虽然每次修改的区间,但是如果从区间的角度考虑不通的话,就要考虑从单点的角度来考虑,去考虑这个点如何能被修改,修改方案对于总体情况来说是否合法。然后这里还有一点就是,在无序数组中寻找第一个大于或小于某个位置的值,用栈来实现。

反思:写题的时候还是要清醒一点,真的就离谱,c题竟然没把最简单的那种情况分析清楚,甚至比较麻烦的两个都分析出来了,下次一定要记住,对于这种操作数确定,而且操作数很大的,一定要找有效操作具体有哪些,或者找当操作数大于某个值后是否所有的操作数都一样,或者找有没有可能每操作多少次,实际变化就循环一次,一定要去找规律,这种肯定不是暴力写的。然后对于区间和单点,它们是相互转化的,涉及到区间的,区间分析不通就要考虑下单点,涉及到单点的,单点不好确定,就要考虑单点能落在哪个区间。另外,对于无序数组的相对位置关系的处理,要考虑用栈实现,本质上就是将冗余部分去掉。


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

相关文章

动手学习深度学习-跟李沐学AI-自学笔记(3)

一、深度学习硬件-CPU和GPU 芯片&#xff1a;Intel or AMD 内存&#xff1a;DDR4 显卡&#xff1a;nVidia 芯片可以和GPU与内存通信 GPU不能和内存通信 1. CPU 能算出每一秒能运算的浮点运算数&#xff08;大概0.15左右&#xff09; 1.1 提升CPU利用率 1.1.1 提升缓存…

jeecg-boot queryFieldBySql接口基于SSTI的任意代码执行漏洞复现 [附POC]

文章目录 jeecg-boot queryFieldBySql接口基于SSTI的任意代码执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议jeecg-boot queryFieldBySql接口基于SSTI的任意代码执行漏洞复现 [附POC] 0x01 前…

Stable Diffusion 系列教程 - 2 WebUI 参数详解

Stable Diffusion 的整个算法组合为&#xff1a; UNet VAE 文本编码器 UNet&#xff1a;就是我们大模型里的核心。 文本编码器&#xff1a;将我们的prompt进行encoder为算法能理解的内容&#xff08;可以理解为SD外包出去的项目CLIP&#xff09;。 VAE&#xff1a;对UNet生…

IDEA如何运行SpringBoot+Vue前后端分离的项目(超详细截图)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

力扣44题通配符匹配题解

44. 通配符匹配 - 力扣&#xff08;LeetCode&#xff09; 给你一个输入字符串 (s) 和一个字符模式 (p) &#xff0c;请你实现一个支持 ? 和 * 匹配规则的通配符匹配&#xff1a; ? 可以匹配任何单个字符。* 可以匹配任意字符序列&#xff08;包括空字符序列&#xff09;。 …

expdp单独导出导入dblink

文章目录 前言一、实现步骤获取ddl方式&#xff08;不可行&#xff09;expdp单独导出dblink 二、impdp单独导入dblink 前言 在实际工作中可能会遇到测试或者迁移工作&#xff0c;对于数据库建立较多的dblink应用重新建立dblink工作量较大&#xff0c;此时可以通过逻辑导出导入…

Linux权限命令详解

Linux权限命令详解 文章目录 Linux权限命令详解一、什么是权限&#xff1f;二、权限的本质三、Linux中的用户四、linux中文件的权限4.1 文件访问者的分类&#xff08;人&#xff09;4.2 文件类型和访问权限&#xff08;事物属性&#xff09; 五、快速掌握修改权限的做法【第一种…

AWR1642 boost开发板支持的TI参考设计

打开radar_toolbox_1_30_00_05\source\ti\examples\examples_overview,通过输入“1642”查找AWR1642 BOOST支持的参考设计,通过筛选,支持AWR1642 BOOST的参考设计如下: 挑选出两个参考设计上手,一个是“nonos_oob_16xx",不带OS;另一个是”short range radar“,比较…