Petrozavodsk Winter 2023. Day 1 部分题解

news2024/11/15 13:35:16

前言:整场的题目质量比较高,虽然之前做过一部分题,但还是被薄纱了

Changing the Sequences

大意:
给定两个数组a,b,长度都为n,元素都介于1-m之间

定义一次操作如下:

构造一个1-m的排列p,对于对于a中的每一个元素,a_i=p_{a_i},得到a'

只进行一次该操作,要求使a'与b的元素不相同的位置尽可能少。并求出满足条件的字典序最小的a'

思路:

显然一次操作的本质是构造一个a到a'的单射。我们可以直接考虑映射的值。将ai与对应的bi连边,表示如果ai的映射是bi,可以造成一个贡献。我们希望最终的贡献尽可能多。显然边的权值可以累加。

所以本质上我们就是在一个二分图上寻找匹配,使得匹配边的权值之和尽可能大。也就是最大权匹配问题。如果不考虑字典序最小的话,我们可以直接用KM来解决这个问题。时间复杂度就是m^3

现在想想如何让字典序最小。说来可以,这其实是一种不算罕见的套路,但是赛时我们队还是全体宕机,但事后看看,并没有想象中的那么不可做。

显然字典序最小的前提是保持权值和最大,然后我们去修改可以连边,使得a数组中靠前的数字尽可能去匹配尽可能小的数字。为了做到这一点,我们先将a数组的元素按位置先后从小到大赋值(因为其本身的元素大小并没有什么用,我们关心的只是元素的位置)。

然后无脑跑一遍KM,得到最大的匹配权值和ans。然后我们尝试修改匹配方案。

外层遍历更新后的a数组,内层遍历映射的域,分别记为i,j。尝试将i的映射变成j,我们需要验证i->j的权值贡献加上图的其他部分的贡献与ans相同。那么将i连向其他点的权值置为0,再将其他点连向j的权值置为0,重新跑一遍KM,加上i到j的权值贡献,即可。如果和与ans相同的话,代表这个匹配是可以的。这里有贪心的成分在,但是因为我们是要字典序最小,前缀越小约好,所以可以贪心。匹配成功后,我们就将两个点从图中去除即可。否则恢复成原来的状态。

code

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define endl '\n'
const int INF=0x3f3f3f3f;
const int N=1e5+10;

int n,m,match[N],pre[N];
bool vis[N];
int favor[70][70];
int val1[N],val2[N],slack[N];
ll a[N],b[N];
ll mp[N],cn;
ll To[70];
ll Pre[70][70];
ll change[70];
ll VIS[70];

void bfs(int p)
{
    memset(pre,0,sizeof pre);
    memset(slack,INF,sizeof slack);

    match[0]=p;

    int x=0,nex=0;
    do{
        vis[x]=true;

        int y=match[x],d=INF;

        // 瀵逛簬褰撳墠鑺傜偣y锛宐fs鏈夎繛杈圭殑涓嬩竴鐐?
        for(int i=1;i<=m;i++)
        {
            if(!vis[i])
            {
                if(slack[i]>val1[y]+val2[i]-favor[y][i])
                {
                    slack[i]=val1[y]+val2[i]-favor[y][i];
                    pre[i]=x;
                }
                if(slack[i]<d)
                {
                    d=slack[i];
                    nex=i;
                }
            }
        }

        for(int i=0;i<=m;i++)
        {
            if(vis[i])
                val1[match[i]]-=d,val2[i]+=d;
            else
                slack[i]-=d;
        }

        x=nex;

    }while(match[x]);

    while(x)
    {
        match[x]=match[pre[x]];
        x=pre[x];
    }
}

ll KM()
{
    memset(match,0,sizeof match);
    memset(val1,0,sizeof val1);
    memset(val2,0,sizeof val2);
    for(int i=1;i<=m;i++)
    {
        memset(vis,false,sizeof vis);
        bfs(i);
    }
    ll ans=0;
    for(int i=1;i<=m;++i) ans+=favor[match[i]][i];
    	return ans;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i) cin>>a[i];
		for(int i=1;i<=n;++i) cin>>b[i];

	for(int i=1;i<=n;++i)
	{
		if(!mp[a[i]]) mp[a[i]]=++cn;
		a[i]=mp[a[i]];
	}

	for(int i=1;i<=n;++i)
	{
		favor[a[i]][b[i]]++;
	}
	for(int i=1;i<=m;++i)
	{
		for(int j=1;j<=m;++j) Pre[i][j]=favor[i][j];//原始数组
	}

	ll ans=KM();//全局最优解

	ll sum=0;
	for(int i=1;i<=m;++i)
	{
		for(int j=1;j<=m;++j)
		{
			if(VIS[j]) continue;
			ll th_val=favor[i][j];
			for(int s=1;s<=m;++s)
			{
				favor[i][s]=0;
				favor[s][j]=0;//除去
			}
			if(th_val+sum+KM()==ans)//代表匹配成功,我们修改它
			{
				VIS[j]=1;
				change[i]=j;
				sum+=th_val;//sum记录之前已经匹配过的映射的权值贡献和
				break;
			}
			for(int s=1;s<=m;++s)
			{
				if(s>=i) favor[s][j]=Pre[s][j];//前面都是已匹配过的点
				if(VIS[s]) continue;//已经连接过
				favor[i][s]=Pre[i][s];
			}

		}
	}
	for(int i=1;i<=n;++i) cout<<change[a[i]]<<' ';

	return 0;
}

Determine The Fluctuation Bonus

大意:

给定n个人,每一个人有一个初始分数为0.q次操作,每次操作给定id,a,第id个人加上a分。每次操作之后所有人按分数重新排序,获得排名变化的绝对值的贡献。

求q次操作之后每一个人的贡献。

思路:

看着难,实际也没那么不可做,还是太怂了

每一个人的分数可以分成两个部分:自己操作带来的贡献,以及别人操作对自己带来的贡献。第一个值其实比较好维护,我们只需要记录每一个人的分数,然后每一次操作的时候维护一下排名,贡献就是排名的变化了,具体实现用一个树状数组T1来维护分数。第二个部分可以用另一个树状数组T2维护。每一次操作之后,分数从pre变成了now,那么只有分数区间在[pre,now-1]之间的人才会获得贡献,并且贡献为1,简单做一个差分即可。

最后一个问题就是如何将两者相加。让第二个树状数组T2记录每一个分数累计获得的贡献。每次操作的时候,对于id,我们然其贡献加上T2(pre),再减去T2(now),即可。因为id之前一直在pre的位置,所以加上这个位置带来的贡献。但是下一次又轮到id操作的时候,它并不是从一开始就待在当前的now这个位置的,所以我们先提前减去T2(now),下一次就可以放心加上对应的值了,实现起来也比较容易。

同时数据值域比较大,我们还要提前离线下来把数据离散化。

写起来有点绕,细节比较多。

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define low(x) x&(-x)
#define endl '\n'
const ll N=2e5+10;
const ll M=2e5;
struct Tree
{
	ll tr[N];
	void add(ll x,ll y)
	{
		while(x<=M)
		{
			tr[x]+=y;
			x+=low(x);
		}
	}
	ll sum(ll x)
	{
		ll ans=0;
		while(x)
		{
			ans+=tr[x];
			x-=low(x);
		}
		return ans;
	}
	ll Gt_sum(ll l,ll r)
	{
		return sum(r)-sum(l-1);
	}
	void upd(ll l,ll r,ll val)
	{
		add(l,val);add(r+1,-val);
	}
}T1,T2;
ll n,q;
map<ll,ll> mp;
struct ty
{
	ll id,val;
}mas[N];
ll pos[N];
set<ll> st;
int idx=0;
ll ans[N];
void solve()
{
	cin>>n>>q;
	st.insert(0);
	for(int i=1;i<=q;++i)
	{
		cin>>mas[i].id>>mas[i].val;
		st.insert(pos[mas[i].id]);
		pos[mas[i].id]+=mas[i].val;
		st.insert(pos[mas[i].id]);
	}
	for(auto s:st) mp[s]=++idx;
	for(int i=0;i<=n;++i) pos[i]=0;

	// for(auto s:st) cout<<s<<" ";
	// 	cout<<endl;

	T2.add(mp[0],n);
	for(int i=1;i<=q;++i)
	{
		ll id=mas[i].id;ll val=mas[i].val;
		ll pre_pos=mp[pos[id]],now_pos=mp[pos[id]+val];
		pos[id]+=val;

		ll pre_lnk=1+T2.Gt_sum(pre_pos+1,M);
		// T2.upd(pre_pos,pre_pos,-1);T2.upd(now_pos,now_pos,1);
		T2.add(pre_pos,-1);T2.add(now_pos,1);
		ll now_lnk=1+T2.Gt_sum(now_pos+1,M);
		// cout<<id<<" "<<pre_lnk<<' '<<now_lnk<<endl;

		ans[id]+=abs(pre_lnk-now_lnk);
		ans[id]+=T1.sum(pre_pos);
		ll mi=min(pre_pos,now_pos);ll ma=max(pre_pos,now_pos)-1;
		T1.upd(mi,ma,1);
		ans[id]-=T1.sum(now_pos);
	}
	// for(int i=1;i<=n;++i) cout<<ans[i]<<" ";
	// 	cout<<endl;
	for(int i=1;i<=n;++i)
	{
		cout<<ans[i]+T1.sum(mp[pos[i]])<<endl;
	}

}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	solve();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/731639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

B - Colorful Stamp

#include<iostream> #include<algorithm> #include<vector> #include<bitset> #include<cmath> #include<set> #include<climits> #include<queue> #include<cstring>//memset头文件 using i64 int64_t; using namespa…

Spring Boot中的会话管理是什么,如何使用

Spring Boot中的会话管理是什么&#xff0c;如何使用 在Web应用程序中&#xff0c;会话是一种存储用户状态信息的机制。Spring Boot提供了会话管理的支持&#xff0c;使得在开发Web应用程序时可以轻松地管理用户的会话信息。本文将介绍Spring Boot中的会话管理是什么以及如何使…

ARM day9 (按键中断控制led亮灭)

key.h #ifndef __KEY_H__ #define __KEY_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_uart.h" #include "stm32mp1xx_exti.h" #include "stm32mp1xx_gic.h"//事件号 #define EXTI_…

特征选择算法 | Matlab实现基于ReliefF特征选择算法的分类数据特征选择 ReliefF

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 特征选择算法 | Matlab实现基于ReliefF特征选择算法的分类数据特征选择 ReliefF 部分源码 %--------------------

机器学习基础之《特征工程(2)—特征工程介绍、特征抽取》

一、什么是特征工程 机器学习领域的大神Andrew Ng(吴恩达)老师说“Coming up with features is difficult, time-consuming, requires expert knowledge. “Applied machine learning” is basically feature engineering. ” 注&#xff1a;业界广泛流传&#xff1a;数据和特…

看完这篇 教你玩转渗透测试靶机Vulnhub——Hackable: III

Vulnhub靶机hackableII渗透测试详解 Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;端口敲门&#xff1a;③&#xff1a;SSH暴力破解&#xff1a;④&am…

java入门概念个人理解之package与import浅析

java入门概念个人理解之package与import浅析 由于近来学习java&#xff0c;遇到了一些在c上没有的概念&#xff0c;将它记http://录下&#xff0c;以自己复习使用&#xff0c;如有不理解妥之处&#xff0c;望大家批评指导。资料均由网上经过自己整合理解而来&#xff0c;如有侵…

Permission denied (publickey,password)问题的解决办法

[15:29:00.146] Terminal shell path: C:\WINDOWS\System32\cmd.exe [15:29:01.703] > root59.110.21.45: Permission denied (publickey,password). 解决&#xff1a; RSA key 登录方法/home/user/ 目录下建立 .ssh/ 文件夹 cd ~/ mkdir .ssh # 注意.ssh文件夹的权限 ch…

STM32+PWM+输入捕获测频

外部时钟&#xff0c;主频64M 定时器1 通道1发出PWM波 频率1K 定时器2 通道1输入捕获&#xff0c;上升沿触发 串口 /* USER CODE BEGIN 0 */ uint32_t time_up_num0;//上升沿计数 float time_frequency;//频率 /* USER CODE END 0 */ 初始换打开定时器 /* USER CODE BEGIN 2 …

ubuntu系统字体太小调整方法,亲测有效,2分钟解决!

背景&#xff1a;我们在ubuntu系统下写程序时&#xff0c;文件夹及文档的字体太小&#xff0c;看起来很累眼&#xff0c;现将字体调大方法记录如下&#xff0c;只需2分钟即可解决&#xff01;&#xff01; 1、打开终端&#xff0c;安装gnome-tweaks sudo apt install gnome-t…

express框架使用express-generator工具

1.全局安装 npm install -g express-generator 2.检测是否安装成功 express -h 3. 快速创建Express应用程序的工具 express -e express-generator 说明&#xff1a;express-e和express-generator都是用于快速创建Express应用程序的工具。express-e是一个命令行工具&#xff0…

基于深度学习的高精度球场足球检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度球场足球检测识别系统可用于日常生活中或野外来检测与定位球场足球目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的球场足球目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5…

什么是操作系统

操作系统&#xff08;Operating System&#xff09; 什么是操作系统 操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有&#xff1a;Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等 操作系统的定位 操作系统的基本功能 操作系统由…

【报告】从GLM-130B到ChatGLM:大模型预训练与微调学习记录

本文主要是记录《【报告】从GLM-130B到ChatGLM&#xff1a;大模型预训练与微调》此次讲座的汇报内容&#xff0c;如有不适请联系删除即可&#xff0c;总结记录内容纯粹为了后面学习使用方便&#xff0c;文档性质的资料还是要比看视频更加方便的。

将Json结构展平

前言 技术群里面一个哥们在群里提了一个问题&#xff0c;怎么把Json的树形结构展平成一层 在线Json格式化工具 将这个JSON 展平成这样 代码 使用方法 static void Main(string[] args) {//将测试对象转换成测试Jsonvar json JsonConvert.SerializeObject(new{Id 1,Name …

【数据分析 - 基础入门之NumPy⑤】NumPy基本操作 - 二

知识目录 前言一、聚合函数二、矩阵操作2.1 算术运算2.2 线性代数2.3 其他数学操作 三、广播机制3.1 广播的原则3.2 案例 四、排序五、文件操作结语相关导读 前言 大家好&#xff01;本期给大家带来的是【数据分析 - 基础入门之NumPy⑤】NumPy基本操作 - 二&#xff0c;收录于…

t113i不查网线启动,内核[ cut here ]崩溃问题解决

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.SDK T113-i_v1.0 3.单板 迅龙TLT113-EVM-A1.1-000 自制底板 # 一、现象 插上网线启动&#xff0c;内核打印信息正常 不插网线启动&#xff0c;内核存在CPU崩溃打印[ cut here ] 二、问题根因 根据错误…

超详细JDK下载与安装步骤

目录 一、创建软件文件夹 二、安装软件 三、配置环境变量 四、 测试环境变量 一、创建软件文件夹 c盘目录创建devloop/Java/jdk1.8文件夹和devloop/Java/jre1.8文件夹 二、安装软件 打开jdk安装包 选择下一步 三、配置环境变量 右击此电脑&#xff0c;点击属性 点击高级系…

leetcode 513. 找树左下角的值

2023.7.7 题意要求是最底层的节点&#xff0c;则用层序遍历是最合适的&#xff0c;每一层遍历将元素放入一个数组中&#xff0c;等到最后一层遍历完之后&#xff0c;取这个数组的第一个元素即为所求节点值。 下面上代码&#xff1a; class Solution { public:int findBottomLe…

OpenCV在一张图片上以不同的透明度添加另一张图片

// 包含必要的OpenCV头文件 #include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv;// 定义全局变量 #define WINDOW_NAME "线