牛客周赛 Round 64(博弈论、思维、构造、LCA、换根DP)

文章目录

  • 牛客周赛 Round 64(博弈论、思维、构造、LCA、换根DP)
    • A. 小红的对错判断
    • B. 小红的幂表达
    • C. 小红的前缀询问
    • D. 小红和小紫的博弈游戏(博弈论)
    • E. 小红的字符串重排(思维、构造)
    • F&G. 小红的树上路径查询(LCA、换根DP)

牛客周赛 Round 64(博弈论、思维、构造、LCA、换根DP)

A. 小红的对错判断

根据题意判断即可。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    string s;
    cin >> s;
    
    string a = "YES", b = "yes";
    
    if(s.size() != 3) cout << "wrong answer" << endl;
    else{
        int flag = 0;
        for(int i = 0; i < 3; i++) flag += (a[i] == s[i] || b[i] == s[i]);
        if(flag == 3) cout << "accept" << endl;
        else cout << "wrong answer" << endl;
    }
    
    return 0;
}

B. 小红的幂表达

从大到小枚举底数,判断是否为整次幂。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int n;
    cin >> n;
    
    cout << n << endl;
    for(int i = n; i >= 2; i--){
        int cnt = 0, x = n;
        while(1){
            if(x % i == 0) cnt++, x /= i;
            else break;
        }
        if(x == 1) cout << '=' << i << '^' << cnt << endl;
    }
    
    return 0;
}

C. 小红的前缀询问

维护每个元素出现的次数,边维护边统计其对答案的贡献。

#include<bits/stdc++.h>

using namespace std;

int main(){
    
    int n;
    cin >> n;
    map<int, int> v;
    long long res = 0;
    for(int i = 1; i <= n; i++){
        int x;
        cin >> x;
        res += v[x];
        v[x]++;
        cout << res << " ";
    }
    
    return 0;
}

D. 小红和小紫的博弈游戏(博弈论)

为了方便表示,把 2 * 2 的矩阵的四个元素定义为 1、2、3、4,如下图所示。
在这里插入图片描述

考虑一种情况:假设元素1 的值为 0。
这时,每次操作只能选择 (元素2,元素4) 或 (元素3,元素4),最多的操作次数:
X = m i n ( v a l u e ( 元素 2 ) + v a l u e ( 元素 3 ) , v a l u e ( 元素 4 ) ) X = min(value(元素2)+value(元素3),value(元素4)) X=min(value(元素2)+value(元素3)value(元素4))
即,要么元素2和元素3拿完,剩下元素4;要么元素4 拿完,剩下元素2和元素3。
下面两个例子对应两个 ‘要么’ :

例1:0 1 3 5
列2:0 6 8 3
分别对应四个元素的value

对于操作次数 X:

  1. 当 X 为奇数时,先手必胜。(例2,操作3次)
  2. 当 X 为偶数时,后手必胜。(例1,操作4次)

对于例1,给四个元素整体加 10,得到例3:

例3:10 11 13 15

这时,对于后手来说,肯定希望通过操作,使得==由’例3‘变为’例1‘==的情况。
是否可行呢?


显然可以,当先手选12时,后手选34;先手选13时,后手选24 …

每轮操作,后手都选先手没有操作的两个元素,即可实现使四个元素整体减一,直到出现==’例1’==,后手必胜。

综上,由特殊情况的后手必胜,得到了一般情况的后手必胜。


进一步思考,在上述情况的基础上,多一手操作,会怎么样?

显然,是先手必胜。

先手只需要第一步操作时,选择多出来的这一手操作,即可转化为 ‘先手’ 变 ’后手‘ 且出现 ’后手必胜的局面‘。


完。


code:

#include<bits/stdc++.h>

using namespace std;

int a[10];

void rotate(){    // 逆时针旋转90°,看图
    int x = a[1];
    a[1] = a[2];
    a[2] = a[3];
    a[3] = a[4];
    a[4] = x;
}

int main(){
    
    int ncase;
    cin >> ncase;
    
    while(ncase--){
        for(int i = 1; i <= 4; i++) cin >> a[i];
        int mn = a[1], mx = a[1];
        for(int i = 1; i <= 4; i++) mn = min(mn, a[i]);
        for(int i = 1; i <= 4; i++) a[i] -= mn;
        while(a[1] != 0) rotate();    // 让 0 在 1 的位置
        int cnt = min(a[4], a[2] + a[3]);
        if(cnt) cout << "kou" << endl;
        else cout << "yukari" << endl;
    }
    
    return 0;
}

E. 小红的字符串重排(思维、构造)

显然,出现最多的字符的个数 <= n / 2 时,有解。

一种排列思路:依次选择出现次数最多的字符与出现次数最少的字符换位置。

对于上述排列思路,会出现一个情况,如下:

a c c d d d e e e e

交换后,中间会剩下两个 d 还在原位,如何处理?

在剩下两个d时,此时交换操作的序列为:

a e
c e
c e
d e

取交换序列的前两次操作中的两个e与剩下的两个d 交换位置,结果为:

d d e e e e a c c d

证明这种方法一定可行:

  • 在交换序列中,序列的长度等于“出现最多的字符的个数”。故而,可用作上述操作的字符的个数 = “出现最多的字符的个数”
  • 出现次数最多的元素 <= n / 2,中间剩下的元素一定不是出现次数最多的字符。故而,中间剩下的元素的个数 <= “出现次数最多的元素”
  • 综上,中间剩下的元素的个数<= 序列的长度 = 可用作交换的元素个数
#include<bits/stdc++.h>

using namespace std;

vector<int> v[30];
pair<int, int> a[30];
queue<pair<int, int> > qu; // 交换序列

int main(){
    
    string s;
    cin >> s;
    int n = s.size();
    for(int i = 0; i < n; i++) v[s[i] - 'a'].push_back(i);
    
    for(int i = 0; i < 26; i++) a[i].first = v[i].size(), a[i].second = i;
    
    sort(a, a+26);
    
    if(a[25].first > n / 2) cout << -1 << endl;
    else{
        int i = 0, j = 25, x = 0, y = 0;
        while(i <= j){
            if(i != j){
                while(x < v[a[i].second].size() && y < v[a[j].second].size()){
                    qu.push({v[a[i].second][x], v[a[j].second][y]}); // 少的放在前 
                    x++;
                    y++;
                }
                if(x == v[a[i].second].size()) i++, x = 0;
                if(y == v[a[j].second].size()) j--, y = 0;
            }
            else{
                for(int z = max(x, y); z < a[i].first; z++){
                	pair<int, int> p = qu.front();
                	qu.pop();
                	qu.push(p);	
                	qu.push({p.first, v[a[i].second][z]});
				}
				i++;
            }
        }
        int flag = 1;
        while(!qu.empty()){
        	pair<int, int> p = qu.front();
        	qu.pop();
        	swap(s[p.first], s[p.second]);
        	if(s[p.first] == s[p.second]) flag = 0;
		}
		if(flag) cout << s << endl;
		else cout << -1 << endl;
    }
    
    return 0;
}

F&G. 小红的树上路径查询(LCA、换根DP)

结论1:在无向图中,对于一个任意一个点 x,到路径(u,v)的距离为: ( d i s t ( u , x ) + d i s t ( v , x ) − d i s t ( u , v ) ) / 2 (dist(u, x) + dist(v, x) - dist(u, v)) / 2 (dist(u,x)+dist(v,x)dist(u,v))/2,其中 d i s t ( u , v ) dist(u, v) dist(u,v) 表示点u 到点v 的距离。

结论2:在树上, d i s t ( u , v ) = d e e p ( u ) + d e e p ( v ) − d e e p ( L C A ( u , v ) ) ∗ 2 dist(u, v) = deep(u) + deep(v) - deep(LCA(u,v)) * 2 dist(u,v)=deep(u)+deep(v)deep(LCA(u,v))2,其中 d e e p ( x ) deep(x) deep(x) 表示x的深度, L C A ( u , v ) LCA(u,v) LCA(u,v) 表示 u 和 v的最近公共祖先。


结论1证明:如下图,对于x到路径(u,v) 有两种情况 x 1 x_1 x1 x 2 x_2 x2,通过黑线和蓝线的关系,可得到 x 1 x_1 x1 x 2 x_2 x2 满足结论1。
在这里插入图片描述

结论2证明:如下图,通过黑线和蓝线的关系,结论2得证。

在这里插入图片描述


推广结论1,一个无向图G中,n个点到路径(u,v)的距离 X = ∑ ( d i s t ( u , x ) + d i s t ( v , x ) − d i s t ( u , v ) ) / 2 , x ∈ 图 G 的点集 X= \sum(dist(u, x) + dist(v, x) - dist(u, v)) / 2,x \in 图G的点集 X=(dist(u,x)+dist(v,x)dist(u,v))/2xG的点集

化简上述公式, X = ( ∑ d i s t ( u , x ) + ∑ d i s t ( v , x ) − n ∗ d i s t ( u , v ) ) / 2 , x ∈ 图 G 的点集 X = (\sum dist(u,x) + \sum dist(v, x) - n * dist(u, v)) / 2,x \in 图G的点集 X=(dist(u,x)+dist(v,x)ndist(u,v))/2xG的点集

对于任一点u,预处理 ∑ d i s t ( u , x ) , x ∈ 图 G 的点集 \sum dist(u,x),x \in 图G的点集 dist(u,x)xG的点集,即所有点到点 u 的距离和。即可快速求出 X。( d i s t ( u , v ) dist(u, v) dist(u,v) 通过结论2 可以方便求出)


D P ( u ) DP(u) DP(u) = ∑ d i s t ( u , x ) \sum dist(u,x) dist(u,x),现在考虑 D P ( u ) DP(u) DP(u) 如何维护,如下左图:

可以把点分为两类,一类为 u 为根的子树内的点,一类为 u 为根的子树外的点。

  • 对于 u为根的子树内的点,设 s u m ( u ) sum(u) sum(u) 表示子树内的点到 u 的距离和
    • 对于叶子节点, s u m ( u ) = 0 sum(u) = 0 sum(u)=0
    • 对于非叶子节点, s u m ( u ) = ∑ ( s u m ( x ) + s z ( x ) ) , x ∈ u 的 s o n sum(u) = \sum(sum(x) + sz(x)),x \in u的son sum(u)=(sum(x)+sz(x))xuson
    • 对于 u 的孩子结点x,以 x为根的子树,通过边 ( x , u ) (x, u) (x,u) 到点 u,共有 s z ( x ) sz(x) sz(x)个点需要走这条边。
  • 对于 u 为根的子树外的点,设 d p ( u ) dp(u) dp(u) 表示子树外的点到 u 的距离和
    • 显然,dp(1) = 0,根节点没有子树外的结点。
    • 考虑换根,如何通过 fu 到 u,需要考虑两类点,如下右图。
      • 对于第 1 部分的点,需要通过边 (fu, u) 到点u,共有 sz(1) - sz(fu) 个点需要走这条边。
        故而,第一部分点的贡献为: d p ( f u ) + s z ( 1 ) − s z ( f u ) dp(fu) + sz(1) - sz(fu) dp(fu)+sz(1)sz(fu)
      • 对于第 2 部分的点,需要通过边 (fu, u) 到点u,共有 sz(fu) - sz(u) 个点需要走这条边。
        故而,第二部分点的贡献为: s u m ( f u ) − s u m ( u ) + s z ( f u ) − s z ( u ) sum(fu) - sum(u) + sz(fu) - sz(u) sum(fu)sum(u)+sz(fu)sz(u)
    • 综上, d p ( u ) = d p ( f u ) + s z ( 1 ) − s z ( f u ) + s u m ( f u ) − s u m ( u ) + s z ( f u ) − s z ( u ) dp(u) = dp(fu) + sz(1) -sz(fu) + sum(fu) - sum(u) + sz(fu) - sz(u) dp(u)=dp(fu)+sz(1)sz(fu)+sum(fu)sum(u)+sz(fu)sz(u)
  • 综上, D P ( u ) = s u m ( u ) + d p ( u ) DP(u) = sum(u) + dp(u) DP(u)=sum(u)+dp(u)
    在这里插入图片描述
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 1e5 + 5;

vector<int> mp[maxn];

ll sz[maxn], sum[maxn]; // sz[x] = 以 X 为根的子树的大小;sum[x] = 以 x 为根的子树中,子树内的点到 x 的距离和 
ll deep[maxn], f[maxn][20]; // dis[x] 表示根结点 x 的深度, f[x][i] 表示 x 向上 2^i 个祖先 
void dfs(int fa, int u){
	deep[u] = deep[fa] + 1;
	f[u][0] = fa;
	for(int i = 1; i < 20; i++) f[u][i] = f[f[u][i-1]][i-1]; 	
	sz[u] = 1;
	for(auto v : mp[u]){
		if(v == fa) continue;
		dfs(u, v);
		sz[u] += sz[v];
		sum[u] += sum[v] + sz[v];
	}
}

ll dp[maxn];	// 注意数据范围,int不行
void dfs2(int fa, int u){
	for(auto v : mp[u]){
		if(v == fa) continue;
		dp[v] = dp[u] + sz[1] - sz[v] + sum[u] - sum[v] - sz[v];	// 转移dp,维护子树外的点的贡献
		dfs2(u, v);
	}
    dp[u] += sum[u]; // 加上子树内的点的贡献
}

// lca
int lca(int u, int v){
	if(deep[u] < deep[v]) swap(u, v);
	
	int d = deep[u] - deep[v];
	for(int i = 0; (1<<i) <= d; i++) if((1<<i) & d) u = f[u][i];
	
	if(u == v) return u;
	
	for(int i = 19; i >= 0; i--){
		if(f[u][i] != f[v][i]){
			u = f[u][i];
			v = f[v][i];
		}
	}
	return f[u][0];
}

// 得到 u 到 v 的距离 
ll get_dist(int u, int v){
	return deep[u] + deep[v] - deep[lca(u, v)] * 2;
}

int main(){
	
	int n, q;
	cin >> n >> q;
	int u, v; 
	for(int i = 1; i < n; i++){
		cin >> u >> v;
		mp[u].push_back(v);
		mp[v].push_back(u);
	}
	
	dfs(0, 1);
	dfs2(0, 1); 
	
	while(q--){
		cin >> u >> v;
		ll res = (dp[u] +  + dp[v] - 1ll * get_dist(u, v) * n) / 2;
		cout << res << endl;
	}
	
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LabVIEW共享变量通信故障

问题概述&#xff1a; 在LabVIEW项目中&#xff0c;使用IO服务器创建共享变量&#xff0c;并通过LabVIEW作为从站进行数据通信。通讯在最初运行时正常&#xff0c;但在经过一段时间或几个小时后&#xff0c;VI前面板出现错误输出&#xff0c;导致数据传输失败。虽然“分布式系统…

equals方法重写--自写Person类

1.Object类的equals方法&#xff08;源码&#xff09; public boolean equals(Object obj) {return (this obj);//判断如果比较的两个对象是同一个对象&#xff0c;则返回true} 2.String类重写Object类的equals方法&#xff08;源码&#xff09; public boolean equals(Obje…

Git的初次使用

一、下载git 找淘宝的镜像去下载比较快 点击这里 二、配置git 1.打开git命令框 2.设置配置 git config --global user.name "你的用名"git config --global user.email "你的邮箱qq.com" 3.制作本地仓库 新建一个文件夹即可&#xff0c;然后在文件夹…

网络一些相关术语

目录 网络一些相关术语 转发平面效率 可扩展性 控制平面 网络拓扑 服务质量&#xff08;QoS&#xff09; 网络协议 网络带宽 网络拥塞 网络安全 网络冗余 网络切片 网络延迟 网络地址转换&#xff08;NAT&#xff09; 虚拟专用网络&#xff08;VPN&#xff09; …

尚硅谷-react教程-求和案例-优化2-Provider组件的使用-笔记

在这篇文章的基础上&#xff0c;https://blog.csdn.net/weixin_41987016/article/details/143257435?spm1001.2014.3001.5501 继续优化&#xff0c; 借助Provider批量的给整个应用里面的所有的容器组件的添加store 原来的,src/index.js import React from "react&quo…

从0开始深度学习(17)——数值稳定性和模型初始化

在每次训练之前&#xff0c;都会对模型的参数进行初始化&#xff0c;初始化方案的选择在神经网络学习中起着举足轻重的作用&#xff0c; 它对保持数值稳定性至关重要。 我们选择哪个函数以及如何初始化参数可以决定优化算法收敛的速度有多快。 糟糕选择可能会导致我们在训练时遇…

云电脑的真实使用体验

最近这几年&#xff0c;关于云电脑的宣传越来越多。 小枣君之前曾经给大家介绍过云电脑&#xff08;链接&#xff09;。简单来说&#xff0c;它属于云计算的一个应用。通过在云端虚拟出一些虚拟电脑&#xff0c;然后让用户可以远程使用&#xff08;仍然需要借助本地电脑&#x…

jupyter notebook改变默认启动路径

安装好Anaconda 3以后,就可以使用Jupyter notebook了,但是我们打开Jupyter notebook后,发现界面是一个默认的目录,这个目录在哪里?如果想把自己写的程序文件保存在自己新建的一个文件夹里,修改默认目录到自建的文件夹下,该如何做呢! 先看一下Jupyter notebook的默认界…

【ubuntu18.04】ubuntu18.04升级cmake-3.29.8及还原系统自带cmake操作说明

参考链接 cmake升级、更新&#xff08;ubuntu18.04&#xff09;-CSDN博客 升级cmake操作说明 下载链接 Download CMake 下载版本 下载软件包 cmake-3.30.3-linux-x86_64.tar.gz 拷贝软件包到虚拟机 cp /var/run/vmblock-fuse/blockdir/jrY8KS/cmake-3.29.8-linux-x86_64…

【华为路由】OSPF多区域配置

网络拓扑 设备接口地址 设备 端口 IP地址 RTA Loopback 0 1.1.1.1/32 G0/0/0 10.1.1.1/24 RTB Loopback 0 2.2.2.2/32 G0/0/0 10.1.1.2/24 G0/0/1 10.1.2.1/24 RTC Loopback 0 3.3.3.3/32 G0/0/0 10.1.2.2/24 G0/0/1 10.1.3.1/24 RTD Loopback 0 4.4.4…

大模型Transformer笔记:KV缓存

1 MHA&#xff08;Multi-Head Attention&#xff09; 最经典的多头注意力 等价于多个独立的单头注意力的拼接 对于LLM来说&#xff0c;一般都是自回归地一个一个token的输出&#xff0c;也就相当于只有Transformer的decoder input在变化&#xff0c;之前作为prompt部分的是不变…

java智能物流管理系统源码(springboot)

项目简介 智能物流管理系统实现了以下功能&#xff1a; 智能物流管理系统的主要使用者分为管理员&#xff0c;顾客&#xff0c;员工&#xff0c;店主。功能有个人中心&#xff0c;顾客管理&#xff0c;员工管理&#xff0c;店主管理&#xff0c;门店信息管理&#xff0c;门店…

【制造业&电子产品】电脑电子元件检测系统源码&数据集全套:改进yolo11-TADDH

改进yolo11-SCConv等200全套创新点大全&#xff1a;电脑电子元件检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.24 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者…

蓝桥杯题目理解

1. 一维差分 1.1. 小蓝的操作 1.1.1. 题目解析&#xff1a; 这道题提到了对于“区间”进行操作&#xff0c;而差分数列就是对于区间进行操作的好方法。 观察差分数列&#xff1a; 给定数列&#xff1a;1 3 5 2 7 1 差分数列&#xff1a;1 2 2 -3 5 6 题目要求把原数组全部…

基于Springboot+Vue的食品商城系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

duilib的应用 在双屏异分辨率的显示器上 运行显示不出来

背景&#xff1a;win11&#xff0c;duilib应用&#xff0c;双显示器&#xff0c;两台分辨率相同&#xff0c;分别设置不同的缩放以后&#xff0c;应用运行以后&#xff0c;程序闪一下消失或者程序还在&#xff0c;但是UI显示不出来。 原因 窗口风格设置不合理&#xff0c;所以…

记录贴 为VScode配置C语言环境

大致步骤参考这位博主的过程&#xff1a;如何在 VS Code 中编写、运行C语言程序 教程_visual studio code怎么写c语言-CSDN博客 第一步&#xff1a;安装VScode。 第二步&#xff1a;安装两个插件&#xff1a;C/C Extension Pack和code runner。&#xff08;后面我发现&#x…

django5入门【03】新建一个hello界面

文章目录 1、前提条件⭐2、操作步骤总结3、实际操作示例 1、前提条件⭐ 将上一节创建的 Django 项目导入到 PyCharm 中。 2、操作步骤总结 &#xff08;1&#xff09;在 HelloDjango/HelloDjango 目录下&#xff0c;新建一个 views.py 文件。 &#xff08;2&#xff09;在 H…

WebGl 缩放矩阵

缩放矩阵是线性代数中的一种矩阵&#xff0c;用于描述图形在空间中沿着各个坐标轴进行均匀缩放的变换。在3D图形编程中&#xff0c;缩放矩阵通常用于调整物体的大小&#xff0c;而不改变其形状。 | x 0 0 0 | | 0 y 0 0 | | 0 0 z 0 | | 0 0 0 1 | 其中&#xff0…

2024 Rust现代实用教程:1.3获取rust的库国内源以及windows下的操作

文章目录 一、使用Cargo第三方库1.直接修改Cargo.toml2.使用cargo-edit插件3.设置国内源4.与windows下面的rust不同点 参考 一、使用Cargo第三方库 1.直接修改Cargo.toml rust语言的库&#xff1a;crate 黏贴至Cargo.toml 保存完毕之后&#xff0c;自动下载依赖 拷贝crat…