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

相关文章

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

前端缓存策略的自解方案全解析

《前端缓存策略的自解方案全解析》缓存从来都是前端的一个痛点,很多前端搞不清楚缓存到底是何物,:本文主要介绍前端缓存的自解方案,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、为什么“清缓存”成了技术圈的梗二、先给缓存“把个脉”:浏览器到底缓存了谁?三、设计思路:把“发版”做成“自愈”四、代码

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java JDK Validation 注解解析与使用方法验证

《JavaJDKValidation注解解析与使用方法验证》JakartaValidation提供了一种声明式、标准化的方式来验证Java对象,与框架无关,可以方便地集成到各种Java应用中,... 目录核心概念1. 主要注解基本约束注解其他常用注解2. 核心接口使用方法1. 基本使用添加依赖 (Maven

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二