vijos题库最终修改完整版.docx
- 文档编号:30248298
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:94
- 大小:98.60KB
vijos题库最终修改完整版.docx
《vijos题库最终修改完整版.docx》由会员分享,可在线阅读,更多相关《vijos题库最终修改完整版.docx(94页珍藏版)》请在冰豆网上搜索。
vijos题库最终修改完整版
VIJOS
【颜色代表内容形式!
!
!
】
题目附件算法正文注意引用说明
1000A+BProblem
数学(?
)
请Ctrlc+ctrlv
programPlus;
vara,b:
longint;
begin
readln(a,b);
writeln(a+b);
end.
注意:
不是高精度加法
程序来自:
VIJOS
1001谁拿了最多奖学金
模拟
仔细点就行了。
1001.pas
1002过河
解法1:
动态规划
设f[i]表示跳到i所能碰到的最少石子数,方程式很容易。
f[i]=min{f[i-t],f[i-t+1]...f[i-s]}+i上的石子数
因为题目中的l非常大,但石子数却非常少,在这种情况下我们会发现f数组有一大段一大段的值都是完全一样的,这时候多算下去也没有意义,设有一段f[i-t]...f[i]完全相同,这时我们完全可以把它们移动到下一个石头的前面去,这样就能节省掉许多时间。
实现中,我们可以用循环数组,方程式完全一样,只不过如果发现i前t个值全部一样时,就直接把i的坐标跳到下一个石子处。
当s=t时我们的方法行不通,因为f数组中不会出现连续的相同值,这时可以特判,石子的坐标mods=0的就会被踩到。
注意:
为了方便,循环数组可从0开始编号;最后一步没说一定要跳到l;判断f[i]到f[i-t]是否相同时可加个优化:
数组g记录以i结尾的连续相同的值有多少个,每次判断g[i]是否大于t就行了,不过本题s,t过小,效果并不明显。
1002.pas
解法2:
动态规划
总体思想和解法1相同,我们可以确定当两颗石子(包括终点和最后一颗石头的距离)的距离大于100时,完全可以将其距离缩短为100(证明我还不会),但注意你把i石子往前推时,i后面的石子(包括终点l)也得一起往前推,这样压缩完之后直接动归就不会超时了。
1002-2.pas
1006晴天小猪历险记之Hill
动态规划
如果只能从下往上走,那么本题会非常简单,但小猪还能左右走,于是只能把从i+1到i层的行动分为2步:
从i+1到I层,再在i层左右移动。
第一步可以很容易用动规做出,第二步需要叠代,在第i层不断地做同层动规,直到没有更优出现为止。
注意:
最左,右两点有5种走法。
1006.pas
1007绕钉子的长绳子
数学
算出多边形的周长,再加上圆的周长即可。
1007.pas
1008篝火晚会
模拟
首先明显地可以知道我们需要对于目标状态建立出一个环。
如果无法建立这个环,那么结果一定是-1,当建立好环以后可以知道最小移动代价一定等于最少的不在目标位置上的人数。
那么我们可以对目标环进行顺时针旋转1~n-1之中任意一个,答案就一定等于旋转中的不在自己位置上的人数最少的那样的环的状态。
但是对于50000的数据,我们如果要将环旋转1~n-1次,那么总共加上判断不在自己位置上的人数时间复杂度为O(n^2),显然在限定时间内是无法出解的。
因此我们进行逆向思维:
不在自己位置上最少的人数就一定会等于总人数减去在自己位置上最多的人数(仔细想想),那么我们就将该问题转化为了求在自己的位置上最多的人数,这样一来,我们对初始目标环中每一个位置进行判断需要旋转多少次可以回到自己位置上,每一个人的选择都将映射到[0..n-1]的数组中,选取当中最大的情况就为所求,但是考虑到环可以反转,那么我们还需要将环再求一次镜像,就可以得到初始目标需要旋转多少次可以得到在自己位置上最多的人数的环的状态,最后通过总的人数减去它即为问题所求,时间复杂度为O(n);
题解来自:
VIJOS
1008.pas
1011清帝之惑之顺治
解法1:
记忆化搜索
就是把己经搜索好的答案存下,下次搜到时调用(本题不存在路程重复问题)。
1011-2.pas
解法2:
动态规划
先将输入的高度全部排序,然后从小到大计算,可以证明:
(x,y)周围四个点要么是以前已计算出解,要么不合法(不能走)。
1011.pas
程序来自:
OIBH
1012清帝之惑之雍正
1012.pas
1014旅行商简化版
动态规划
先把所有点按横坐标从左到右排序。
把题目理解为两个人A1,A2从最左边的点走到最右边的点,一个点不能被两个人走。
f[i,j]表示A1,A2分别走到i,j时的最小花费,同时从最左边到i,j的点都要被走到过且不能重复,我们假定i>j。
动归方程要注意路的连续性。
当i=j+1时,f[i,j]=min{f[i-1,k]+dis(k,i)}k<=j
当i>j+1时,f[i,j]=f[i-1,j]+dis(i-1,i)
初始f[1,1]=0
注意:
初值得赋得大点,2E20。
1014.pas
1016北京2008的挂钟
解法1:
广搜
广搜,注意开数组记录(9维)已经到过的状态。
1016.pas
解法2:
枚举
每种方法用了4次之后就等于没有用,所以枚举每个方法的使用次数,然后判断是否结束就行了。
1016-2.pas
程序来自:
VIJOS
1019补丁VS错误
位运算
由于错误最多只有15种,因此可以用2进制表示状态。
看出位运算之后DFS,BFS,SPFA都行了,注意不要一开始把边都连上去,搜到一个状态时,枚举每个补丁并用位运算来判断是否可拓展。
我用了SPFA。
1019.pas
1021Victoria的舞会1
本题有两种理解方法。
1:
全部的人都会参加舞会。
模拟
只要统计每个人的伙伴个数是否大于k就行了。
1021.pas
2:
愿意交流的人数小于k的人不会参加舞会。
“踢人法”(题解上看来的,我还是忠于原著吧,明明是叠代好不好。
。
。
。
。
。
)
先把伙伴个数小于k的人踢了,这些人不会参加舞会,所以会影响到和他们是伙伴的人(题目中说了“如果A名单里面有B,那么B名单里面肯定有A”,所以我们要把与被踢的人有关系的人的伙伴数减1,如果他们被伙伴数被减得小于k就会发生第一行说的事情。
。
。
。
。
。
(递归)
1021-2.pas
注意:
如果一个人被踢过了,就要标上记号表示他已经被踢过了,不能再踢了(什么话),否则会出错的。
1022Victoria的舞会2
求强连通分支
用标准求强连通分支算法。
最后输出一共有多少个强连通分支就行了。
1022.pas
1023Victoria的舞会3
图论
先把必须要通知的点通知,就是那些入度为0的点,把它们进行拓展,拓展到的点都标上记号。
然后在找环的个数,最后结果就是入度为0的点个数+环的个数。
1023.pas
1024卡布列克圆舞曲
模拟
数字太大不能用布尔数组判重,只好把每一个都存下来了,每次得到的新数都和前面的看一遍是否相同。
组成最大最小用排序就行了(不要傻傻地排两遍),用qsort就有点杀鸡用牛刀了。
。
。
。
。
。
1024.pas
注意:
要选择自己认为方便的存储方法(如字符串);位数不足时要补0;虽然题目说小于maxlongint,但组成最大数后还是可能会超,用int64。
1025小飞侠的游园方案
动态规划
用f[I,j]表示用前i个地点,时间为j的最大高兴度。
F[I,j]=max{f[i-1,j],F[i-1,j-a[i]]
简单的背包。
1025.pas
1026毒药?
解药?
解法1:
广搜
用二进制表示状态,本题用相同的药,顺序换一下结果可能结果不同。
所以用病人当前治愈了哪些病作为状态(一开始当患上了所有病),对于状态i,使用药j后的状态用二进制运算or和and能很方便地表示出(当然药效也要用二进制表示),要判重。
1026.pas
注意:
若某种病以前已经治愈过,而现在的药会使病人再患上,那现在还是会患上的;有无解情况。
解法2:
dijkstra
把每一个状态都作为点,每个点都用每个药作为边,建图。
1026-2.pas
程序来自:
VIJOS
1028魔族密码
解法1:
O(n2)动态规划
最长不下降子序列,用s[i]表示第i个字符串的最大连续数。
S[i]=max{s[j]}|j=1,2…i-1,pos(a[j],a[i])=1
1028.pas
解法2:
O(n)动态规划
我们注意到题目中说的按字典顺序排列,于是得出若i 于是用一个栈把个字符串都存下来,之后每次不断出栈,若符合条件就加上,不符合直接就扔掉(符合条件的那个仍要存在栈中哦)。 这个可能算不上动态规划吧。 。 。 。 。 。 1028-2.pas 1030重叠的方框 搜索 在读入中,我们可以获取每个字母矩形的左上角和右上角(就是横纵座标最小和最大的合并),这样就能确定一个矩形。 然后开始搜索,注意搜索过程中我们倒过来,先搜最后放的矩形,就是说,在搜索的过程中,如果发现目前要放的顶点上已经有了字母,就说明这个点已经被覆盖掉,不能再放了(因为是倒过来搜的)。 同时,这次每个放的点已经确定了,我们可以直接拿它去和原始图比较(别整张图去比,比这次画的矩形就够了),如果不同,直接就可以退出了,这样的剪枝是十分强的。 1030.pas 1033整数分解(版本2) 数学 把数一直分3,分到4直接乘,要高精度 1033.pas 1034家族 并查集 简单的并查集,加了路径压缩后就很快了。 注意: 是Yes,No不是YES,NO。 1034.pas 1035贪婪的送礼者 模拟 难点就是名字,要把每个名字都编上号,然后查找出号码。 1035.pas 1036安装服务器 带权中位数 首先要把x轴和y轴分开处理。 每个点上有个权,然后费用总和为所有点到选定点的距离乘上它的权,如果每个点有个权k,我们可以把这个拆成坐标相同的k个点,这时我们发现问题转化为不带权的中位数问题了! 不带权的中位数问题就是排序之后找到当中的那个点,而这里我们就是要找到从点1到它的权值部分和正好等于总权值一半的那个点。 于是我们可以先把所有点按坐标排序,然后从头开始扫描,到权值和正好大于等于总权值和一半的时候就是答案了。 另外SFR介绍了一个线性求带权中位数的方法: 在区间[first,last)内查找中位数时,用一个变量s1表示在序列中所求的带权中位数到first这一段的权值之和(设带权中位数下标为idx,则ΣW[first..idx]≥s1,W[idx+1..last] 用快速选择(快速排序的应用)找到不带权的序列的中位数。 设mid=(first+last)/2,如果cnt=ΣWi(i∈[first,mid))≥s1,说明整个序列的带权中位数在区间[first,mid)内;如果s1-cnt>Wnid,说明整个序列的带权中位数在区间[mid,last)内;否则,Amid就是带权中位数。 #include #include usingnamespacestd; structnode { intx,w; booloperator<(constnode&rhs)const { returnx } }a[100000],b[100000]; intMedian(node*first,node*last,ints1,ints2) {//在区间[first,last)内查找中位数 intn=last-first; if(n==1)returnfirst->x; intcnt=0; node*mid=first+n/2; nth_element(first,mid,last); for(node*p=first;p cnt+=p->w; if(cnt>=s1)returnMedian(first,mid,s1,cnt-s1); if(s1-cnt>mid->w)returnMedian(mid,last,s1-cnt,s2); returnmid->x; } intmain() { inti,n,s,w=0; scanf("%d",&n); for(i=0;i { intt1,t2; scanf("%d%d%d%d",&a[i].x,&b[i].x,&t1,&t2); a[i].w=t1*t2;b[i].w=a[i].w;w+=a[i].w; } printf("%d%d\n",Median(a,a+n,w/2,w/2),Median(b,b+n,w/2,w/2)); } 1036.pas 1037搭建双塔 解法1: 动态规划 用f[I,j]表示用前i个水晶,差距为j,搭成的两个塔中较高的那个塔,有了f[I,j],j就能得出f[I,j]下的高塔和矮塔。 现在看新的第i个水晶,三种情况: 1不用f[I,j]=f[I-1,j] 2放在高塔f[I,j+k]=f[i-1,j]+k 3放在低塔f[I,abs(j-k)]=max(f[i-1,j],f[i-1,j]-j+k) 当前高塔加上i水晶后的低塔(可能超过前者) 初始s[0,0]=0其他-1 最后输出s[n,0] 注意: 为了编程方便,可以把数组开大些防止超界;有impossible的情况; 1037.pas 解法2: 第推 F[I,j]表示(I,j)的高度能否达到,初始f[0,0]=true其他全部false,最后找f[i,i]=true的i最大 这么做谁都会,但是在时间限制危险的情况下如何猥琐地缩短时间就是大家要考虑的了 枚举优化: 1不用每次从2000开始往下,可以记录一个当前最大值 2最后枚举答案时从后往前(够猥琐) 1037-2.pas 1038添加括号 题目有两个地方说错了,输出和的顺序是从左到右,从里到外。 还有本题是有多解情况的,在动规寻找分割点时请让分割点尽量靠右(<改成<=)。 动态规划 题目是石子合并,不想说了,因为难点不在这里。 动规时要把分割点记录下来,接着做深搜,主要输出都在DFS中完成,先把外层括号写了,然后由记录下的分割点继续二分递归,当中加入+号,最后把当前的和按顺序存在ans数组中(由题意,这步应该最后做)。 1038.pas 1040高精度乘法 高精度计算 本题数位过大,所以不能一位一位地乘,所以把两个乘数分成4位4位地存在数组中(比如12312340010,存成123,1234,10),然后和原来一样做高精度乘法(当然不是div10,mod10了,是10000),最后输出时也是4位地输出,要注意,如果ans[i]不足4位,要补0。 1040.pas 1041神风堂人数 枚举 本题的解不存在连续性(如15人对,16人就错),不能二分,所以只能枚举。 注意: 精度问题 1041.pas 1042捕风捉影 枚举 将n,m之间的回文数全部枚举出,然后判质数。 因为能被11整除的数,其奇数位的和与偶数位的和之差能被11整除,反过来也一样。 所以,位数为偶数的回文数就可以不用枚举了(但11是的,不要忘记)。 枚举回文数的前半段,然后用字符串加上后半段,如果是质数,就直接输出(不用排序,因为同样的数位,高位在不断的上升,所以数列必是递增的)。 1042.pas 1045Kerry的电缆网络 最小生成树 典型的最小生成树。 1045.pas 1046观光旅游 解法1: dijkstra 枚举每条边,把这条边删掉,然后找这两点的最短路,加上这条边的权便是这个圈的大小。 加个优化就能过: 如果这条边已经比当前的最小值大了,就不管他了 1046.pas 解法2: floyd 在floyd的同时,顺便算出最小环 g[i][j]=i,j之间的边长 dist: =g; fork: =1tondo begin fori: =1tok-1do forj: =i+1tok-1do answer: =min(answer,dist[i][j]+g[i][k]+g[k][j]); fori: =1tondo forj: =1tondo dist[i][j]: =min(dist[i][j],dist[i][k]+dist[k][j]); end; 最小环改进算法的证明 一个环中的最大结点为k(编号最大),与他相连的两个点为i,j,这个环的最短长度为g[i][k]+g[k][j]+i到j的路径中,所有结点编号都小于k的最短路径长度。 根据floyd的原理,在最外层循环做了k-1次之后,dist[i][j]则代表了i到j的路径中,所有结点编号都小于k的最短路径. 综上所述,该算法一定能找到图中最小环。 1046-2.pas 题解来自: VIJOS 1051送给圣诞夜的极光 深搜 照题目的意思,与一个点A有连接的点应有: B BBB BBABB BBB B 我们用标记法,若枚举到一个点没有标记过,就开始深搜,把与这个点有关系的全部点都标上号,并且总数+1。 1051.pas VIJOS1052贾老二算算术 高斯消元法 直接做高斯消消元。 注意: 输出round(ans),否则可能出现-0的输出。 1052.pas 1053Easysssp 本题的题解中牛们说了许多种方法,可以去看看。 图论-SPFA 先把所有dis清0,把所有点加入队列,然后做SPFA,如果有点入队次数超过n次就算有负环,原理和bellmanford差不多。 没有负环就做一次正统SPFA求解便可。 注意: dis数组要用int64;可能有重边,保留比较小的那条。 1053.pas 1055奶牛浴场 枚举 可以想到,最优矩形的四边上必定都有点存在,否则向没有点的那边拓展就能更优。 把坐标按横坐标排序,设目前矩形的左边正好靠在一个点i上,然后设两个变量,分别表示当前矩形的上界和下界。 然后从左往右扫描,一边维护这两个变量,目前扫描到结点j,先将(x[j]-x[i])*(上界-下届)与最大值比较,再看如果j的纵坐标在上下界之间,就修改它们。 这是从左往右扫,我认为还需要从右往左扫一遍,从上往下扫一遍,从下往上扫一遍(可以通过旋转点阵来实现)。 。 。 不知怎么的题解上面很多人扫一遍就过了,不知道是数据弱还是我想错了。 注意: 最优解在围场边上的情况。 1055.pas 1056图形面积 离散+线段树 因为数据过大,我们需要先将纵坐标离散,就是先将纵坐标排序,然后重新赋值,第一小的赋成1,第二小的赋成2...注意两个相同的数值不能离散成相同的值,因为顺序不能变换。 离散完之后开始线段树,先把点按横坐标排序,然后把每个矩形的两条纵边(左边和右边),按横坐标的顺序依次加入线段树中,当前边为左边是加入树,为右边时是删除出树,每次有新的点i,就把面积加上(x[i]-x[i-1])*线段树的长度。 不过离散之后,因为点比较少,直接开布尔数组强行枚举也行的。 。 。 。 。 。 1056-2.pas 程序来自: JLH 注意: 第4个数据有误,左下角的纵坐标大于右上角的纵坐标了,请把这种点忽略掉。 1056.pas 1057盖房子 解法1: 枚举+部分和 先用部分和把每个区域([0,0]……[x,y])的不合法个数记录,然后直接3次方枚举判正方形是否存在(使用部分和O (1)判是否存在)。 1057.pas 解法2: 动态规划 F[I,j]表示以[I,j]为右下角,能找出的最大正方形边长。 F[I,j]=min(f[I,j-1],f[i-1,j-1],f[i-1,j])+1.|a[I,j]=1 初始全0 可以证明,三者中的最小值正方形加上[I,j]补出的一圈(应当说多出的两条边)所形成的图形必然存在。 1057-2.pas 1059积木城堡 背包 做n次背包,然后找共有的最大值 注意: 题目不是说移动积木,是去除积木(我因为这个想了2天);有无解情况。 1059.pas 1060盒子 解法1: 第推 用第推算出,n个盒子只放A球或B球各有几种方法。 最后两者相乘。 F[I,j]表示i个球,放进j个盒子有几种方法, F[I,j]=f[0,j-1]+f[1,j-1]+…+f[I,j-1]就是枚举第j个盒子放几个球,题解上说用qowrd,我用了高精度怎么还过不了,不知道为什么。 。 。 。 。 。 。 1060.pas 解法2: 数学 思想和解法1一样,用组合数学算出只放A球或B球各有几种方法。 最后两者相乘。 ca=c(n+a,a)cb=c(n+b,b) 1060-3.pas 注意: 用qword。 解法3: 动态规划 用f[k,I,j]表示用k个盒子,装i个红球,j个蓝球的方法数。 F[k,I,j]=∑f[k-1,i-a,j-b]|a<=I,b<=j 就是枚举第i个盒子装a个红球,b个蓝球 1060-2.pas 注意: 用qword。 1061迎春舞会之三人组舞 动态规划 设读入数据存于数组k。 显然,在排好序后,取a,b时取相邻的总比取不相邻的要好。 本题把数据倒过来读会比较简单(下面方程式基于此)。 F[I,j]表示分成i组,j个人的最小值。 F[I,j]=min{f[I,j-1]k[j]不用 F[i-1,j-2]+sqr(k[j]-k[j-1])用k[j],k[j-1]} 在有了a,b后,中间的那个人c,需要c>a,c>b,所以c的下标必在a,b前面,又因为a和b相邻,因此循环的时候要有j>=i*3。 最后答案就是f[m,n] 1061.pas 1062迎春舞会之交谊舞 解法1: 模拟 根据题目可知,第一个女生左边的人一定是个男生,而且是她的舞伴,第二个女生的舞伴一定是左边离她最近的男生(刚才那个不算)。 。 。 。 。 。 由此类推。 于是,根据数据,我们能很快把一排人的性别都算出。 对于第i个女生,她左边的靠着她的男生数是a[i]-a[i-1](可能是0),然后我们拿个最近的来就行了。 时间O(n2),可能超时。 于是我们用栈把已知男生的位置都存下,然后依次进出栈便可,时间O(n)。 1062.pas 注意: 题目说的距离是相隔的男生个数;范围有问题,数组开大点; 解法2: 数学 D数组为输入 2种情况 当d[i]>d[i-1]时,i女生只要和她左边的人配就行了,所以输出1 当d[i]=d[i-1]时,i女生要找的是最近的没有配好的男生 接下来我们要的目的就是找到最近的男生 当第i个和第i-1个女生之间有男生没有搭配时(就是d[i]>d[i-1]+1),我们将这些没有配好的男生的位置记在l数组,用f数组记录他们的数量。 把l,f看成一个栈,每次出栈便可。 1062-2.pas 程序来自: VIJOS 1063迎春舞会之集体舞 动态规划 本题的等边三角形分为顶向上,顶向下两种形状。 我们先看顶向上的。 F[I,j]表示以点[I,j]为顶点的等边三角形,显然j必须满足jmod2=0,还有[I,j]的人必须穿夏
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- vijos 题库 最终 修改 完整版
![提示](https://static.bdocx.com/images/bang_tan.gif)