2021统一省选 A卷 day1解析

2024-05-11 00:58
文章标签 统一 解析 2021 day1 省选

本文主要是介绍2021统一省选 A卷 day1解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题面,就参照洛谷的吧。

  1. 卡牌游戏
  2. 矩阵游戏
  3. 图函数

重点看思维过程。

卡牌游戏

  1. 爆搜的话,过前两个点没问题。枚举要翻牌的数量m,然后从n张中翻m张,直接统计最大最小值。

  2. 考虑到卡牌是按照正面数值由小到大排序的,设c[]数组,将a[]和b[]存入c[],然后由小到大排序。枚举最小值minn为c[i],最大值maxn为c[j],这两个值是不可更改的,现在转为判定性问题,注意minn和maxn不能是同一张牌的,要判别一下。那么正面数值在这个区域的,是不用翻牌的。对于正面数据a[]来说,假设最小值minn的下标为i,最大值maxn的下标为j。如下:
    在这里插入图片描述
    那么区间[i,j]是不需要翻牌的。区间[1,i-1]和[j+1,n]是需要翻牌的。最后看确定的最小值和最大值的下标是否在翻牌区域,如果不在翻牌区域,需要m减1或者减2,有几个不在翻牌区域,就减几个。然后只要满足:翻牌数量小于等于m和翻牌区间的最值在minn和maxn之间,就是合法解。。用ST算法维护区间最大值和区间最小值即可。整体复杂度是O(n^2)的。可以过前4个点。

  3. 以上思路稍加调整就可以过第5~6个点。虽然n值较大,达到了5e5,但是m值最大1000。因此枚举的时候,直接枚举前半段翻牌的长度为x,则后半段翻牌的长度最大为m-x。其余同思路2。整体复杂度是O(m^2)。

  4. 为了加速上述的判定,可以用二分法,就是二分答案。这个题目的答案具有单调性,可以转为判定性问题。假设极值为x,现在假定最小值为minn,那么最大值maxn为minn+x。最大和最小值都得是卡牌上的数值。ai值小于minn的部分需要翻牌,而且得保证翻出的牌的最值在minn和maxn之间,ai值大于maxn的也需要翻牌,而且得保证翻出的牌的最值在minn和maxn之间。否则,这组不满足,跳过。
    如何确定最小值minn呢?需要正面和反面的数值一起,设数组c[],依次存入a[]和b[],然后排序,由小到大,需要记下c[]中的数据在原先数列中的下标。用map就可以。因为2n个数据都不相同,所以不矛盾。在c[]中依次枚举作为最小值。最后看确定的最小值和最大值的下标是否在翻牌区域,如果不在翻牌区域,需要m减1或者减2,有几个不在翻牌区域,就减几个。然后只要满足:翻牌数量小于等于m和翻牌区间的最值在minn和maxn之间,就是合法解。枚举时复杂度O(n),查询最值O(logn),共二分次数O(logn),整体复杂度为O(lognnlogn)。可以过全部点。

矩阵游戏

发现由 b i , j b_{i,j} bi,j倒推出 a i , j a_{i,j} ai,j有很多种方法。比如:对于b[1][1],a[1][1]=a[1][2]=a[2][1]=b[1][1]/4,a[2][2]=b[1][1]/4+b[1][1]%4。其他的位置填的话,只需要再确定两个值就可以了,一个值可以填b[][]/2,另一个值填b[][]/2+b[][]%2。这样倒推出来的是没有限制的a[][]。注意限制是:a[i][j]>=0&&a[i][j]<=1e6。我们发现对于某一列,如果从上到下依次加减相同的值,不影响正确性。比如:+x,-x,+x,-x,……,也可以从减开始,比如:-x,+x,-x,+x,……。对于某一行,也是这样。

下面的问题就是如何由得到的一个随机矩阵,通过某种方法转化为合法矩阵。

对于n,m<=3和m=2的情况,感觉应该可以暴力过,但是想不到好的方法。因为按照上面的思路,如何将随机矩阵转化为合法矩阵,总要用到差分约束,也不是暴力做法。直接考虑全部数据规模。

对于奇数行,在行上的改变从加开始,对于偶数行,从减开始。

对于奇数列,在列上的变化从减开始,对于偶数列,从加开始。

在这里插入图片描述
对于某个位置,要经过行上的和列上的变化。这些变化要同时满足所有位置,得列不等式方程组。比如对于(1,1),需要满足: a [ 1 ] [ 1 ] + x 1 − y 1 > = 0 a[1][1]+x1-y1 >= 0 a[1][1]+x1y1>=0 && a [ 1 ] [ 1 ] + x 1 − y 1 < = 1 e 6 a[1][1]+x1-y1 <= 1e6 a[1][1]+x1y1<=1e6。所有的位置都要满足上述类似的要求。

这就最终能化成类似这样的不等式:a<=x1-x2<=b,这个不等式可以拆成:x1<=x2+b和x2<=x1+(-a)。典型的差分约束系统,用最短路解就可以了。总共是n+m个点,n*m条边。spfa可以过。

图函数

几乎每次大考中都会有这种重新定义的题目,一般比较绕,但是跟着样例模拟一遍,就能大致明白它的套路。

n<=10的前4个点,可以直接模拟过。判断两个点是否连通,可以用dfs搜。链式前向星存图,用vis[]对每条边打标记,删除某条边,就是vis置为0。

以下有点长,但不难理解,耐心阅读。

再具体考虑。对于图G,对于点u,判断点v是否能和点u构成点对,那么点v应该满足什么条件呢?首先要明确的是点u和点u能构成点对,然后消去自身,因此v<u。v->u和u->v之间的点满足什么条件呢?之间的点都是>v的。假设v->u和u->v之间存在点x,而且x<=v。那么x->u和u->x之间也是连通的,这样x及其边要被消去,因此等到枚举到v时,x已经不存在了。假设矛盾。

明白这一点的话,也就没必要真正地删除边了,只需要做一些转换。对于任意的图G,有两点v和u,v<u,如果v->u和u->v之间的点都是>v的,那么u和v构成点对。本题求的分别是原图G的点对数,删除一条边的点对数,删除两条边的点对数,……,删除m条边的点对数。真的要一个图一个图的去求吗?肯定不会。应该能想到,这些m+1个图,会有某种连续性。

假设上述对应的图分别为G0,G1,G2,……,Gm。有两点v和u,v<u。v->u和u->v某条路径上的边的最小值为i,也就是说v->u和u->v的路径至少会到删除第i次边的时候才会被破坏。也就是说点u和v,对于图G0,G1,G2,……,Gi都是点对。v和u之间双联通的路径会只有一条吗?也许不会,所以要求出v和u之间所有路径边的最小值的最大值。因为我们希望u和v能产生更多的贡献,所以要最大值。设数组f[i][j]用来记录合法点对i和j之间的边的编号的最小值的最大值,那么上述u和v对答案的贡献就可以用min(f[u][v],f[v][u])来表示。

设数组g[i]表示第i条边对其前面的图的贡献,前面的图指的是:G0,G1,……,Gi-1。想求第i个图总共有多少点对,只要求出第i条边后面的边对它的贡献即可,也就是后缀和。

现在难点就是如何求这个f[i][j]?可以用floyed。首先要明白:对于floyed,在最外层循环到k时,dis[i][j]最短路径上除了i和j两点,路径上的其他结点编号都小于等于k。我们在学习最小环问题的时候讨论过这个问题。

在这里插入图片描述
以下是最小环问题的算法。

在这里插入图片描述
我们要计算f[i][j],假设i<j,要求是i->j和j->i之间的点都是>j的,如何保证在floyed的过程中f[i][j]的点满足这个条件?只要将松弛点k从大到小枚举就搞定了!这样在做到f[i][j]时,上面的点除了i和j外都是大于j的。

可参考以下代码,1000的规模的floyed开o2,居然能过。

#include<cstdio>
using namespace std;
int n,m,x,y,f[1010][1010],g[200010],ans[200010];
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),f[x][y]=i; for(int k=n;k>=1;k--)for(int i=1;i<=n;i++)if(f[i][k]){if (i>k){for(int j=1;j<k;j++)f[i][j]=max(f[i][j],min(f[i][k],f[k][j]));}else{for(int j=1;j<=n;j++) f[i][j]=max(f[i][j],min(f[i][k],f[k][j]));}}for (int i=1;i<=n;i++)for (int j=i+1;j<=n;j++)g[min(f[i][j],f[j][i])]++;ans[m+1]=n;for(int i=m;i>=1;i--)ans[i]=ans[i+1]+g[i];for(int i=1;i<=m+1;i++)printf("%d ",ans[i]);return 0;
}

备注:代码转载自洛谷“永恒之眼”的博客。

这篇关于2021统一省选 A卷 day1解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978063

相关文章

gradle第三方Jar包依赖统一管理方式

《gradle第三方Jar包依赖统一管理方式》:本文主要介绍gradle第三方Jar包依赖统一管理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景实现1.顶层模块build.gradle添加依赖管理插件2.顶层模块build.gradle添加所有管理依赖包

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

Python使用getopt处理命令行参数示例解析(最佳实践)

《Python使用getopt处理命令行参数示例解析(最佳实践)》getopt模块是Python标准库中一个简单但强大的命令行参数处理工具,它特别适合那些需要快速实现基本命令行参数解析的场景,或者需要... 目录为什么需要处理命令行参数?getopt模块基础实际应用示例与其他参数处理方式的比较常见问http

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

Java的栈与队列实现代码解析

《Java的栈与队列实现代码解析》栈是常见的线性数据结构,栈的特点是以先进后出的形式,后进先出,先进后出,分为栈底和栈顶,栈应用于内存的分配,表达式求值,存储临时的数据和方法的调用等,本文给大家介绍J... 目录栈的概念(Stack)栈的实现代码队列(Queue)模拟实现队列(双链表实现)循环队列(循环数组

java解析jwt中的payload的用法

《java解析jwt中的payload的用法》:本文主要介绍java解析jwt中的payload的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解析jwt中的payload1. 使用 jjwt 库步骤 1:添加依赖步骤 2:解析 JWT2. 使用 N

Python中__init__方法使用的深度解析

《Python中__init__方法使用的深度解析》在Python的面向对象编程(OOP)体系中,__init__方法如同建造房屋时的奠基仪式——它定义了对象诞生时的初始状态,下面我们就来深入了解下_... 目录一、__init__的基因图谱二、初始化过程的魔法时刻继承链中的初始化顺序self参数的奥秘默认

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析