2023牛客暑期多校训练营6

news2024/7/7 16:41:15

参考2023牛客暑期多校训练营6(G、E、C、B、A) - 知乎 (zhihu.com)

纯数学,推式子

从贡献度的角度考虑

首先,当两个子集大小均相同时,才有可能变相同

其次是我们需要先将S和T中的数分别从小到大排个序,然后要变相同花费最小,肯定是对齐的数之间变换,可以举个例子感受一下,然后直接记结论

我们从S中找一个数Si,从T中找一个数Tj,它们作为1对,分别放入A和B中,然后它们的贡献度即为它们之间的差的绝对值乘包含这一对数的组合数(即符合条件的包含这一对数一共有多少种排列组合,保证Si时A中第x大的数,Tj也是B中第x大的数,这样对齐了,算的才是变成相同的最小花费),然后我们只要将每一对数的贡献度全部加起来即可 

现在的关键就是如何求组合数,我们这样考虑,假设我们找了Si,Tj这样一对数,首先需要保证它们分别是A中第x大的数和B中第x大的数,现在我们要做的是在S中选择x-1个小于Si的数放在A中,在T中选择x-1个小于Tj的数放在B中,然后就是在S中选择y个比Si大的数放在A中,在T中选择y个比Tj大的数放在B中

我们只要枚举x从0到min(i-1,j-1),枚举y从0到min(n-i,n-j),就可以列举出所有情况,将全部的组合数加起来就可以了

但是这样的话,每次求组合数都是O(n),肯定会超时,我们需要设法通过变形使得求组合数为O(1)

我们设函数g(i,j),有

可以这样理解:我们有i个红球,j个蓝球,我们要不管颜色地从中选取i个,即C(i+j,j),然后我们也可以这样选,就是从j个蓝球中选x个,从i个红球中选取i-x个,这样的话,就是C(i,i-x)*C(j,x),然后我们枚举x从0到min(i,j),就是所有情况,加起来就相当于不管颜色地从i+j个球中选择i个(为什么不是写C((i+j),min(i,j),因为C(i+j,i)等于C(i+j,j),所以无所谓是i还是j)

所以最后组合数就是

对于快速求组合数,我们可以先预处理阶乘和阶乘的逆元 

AC代码: 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<cstdio>
#define endl '\n'
#define int long long
using namespace std;
typedef long long ll;
const int N=4e3+10,mod=998244353;
int s[N],t[N];
int fac[N],ifac[N];
int n;
int qmi(int a,int k){
    int res=1;
    while(k){
        if(k&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        k>>=1;
    }
    return res;
}
//求组合数
int C(int n,int m){
    if(n<m) return 0;
    return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
void solve()
{
    cin>>n;
    fac[0]=ifac[0]=1;
    for(int i=1;i<N;i++) fac[i]=1ll*fac[i-1]*i%mod;//预处理阶乘
    ifac[N-1]=qmi(fac[N-1],mod-2);
    for(int i=N-2;i>=1;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;//预处理阶乘的逆元
    for(int i=1;i<=n;i++) cin>>s[i];
    for(int i=1;i<=n;i++) cin>>t[i];
    sort(s+1,s+1+n);
    sort(t+1,t+1+n);
    int res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            res=(res+abs(s[i]-t[j])%mod*C(i-1+j-1,i-1)%mod*C(n-i+n-j,n-i)%mod)%mod;
        }
    }
    cout<<res<<endl;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--)
        solve();
    return 0;
}

C.idol!!

大致题意是给你一个n,然后求出1!!*2!!*...*n!!末尾有几个0

数学知识,先推式子

发现只有2和5相乘能得到1个0,所以问题就就转换成了有几对2,5组合,但是由于因子5的个数肯定少于因子2的个数,所以我们只要算出因子5的个数即可

n可达1e18,然后又是双阶乘,5的个数肯定会爆long long,所以我们考虑使用更大的数据类型__int128,但是使用__128int需要自己手写输入输出函数

 

我们先考虑样例,n为11时,我们分奇偶来看,当为奇数时,就看因子5的个数,当为偶数时,就看因子也看因子5(10可分解为5*2,也有因子5)的个数,故末尾一共5个0 

奇偶分开来考虑:

对于奇数,我们会发现,从5开始,即5!!,7!!,9!!,....

每5个数贡献度+1

比如说

5!!=1*3*5,7!!=1*3*5*7,9!!=1*3*5*7*9,11!!=1*3*5*7*9*11,13!!=1*3*5*7*9*11*13,这5个数贡献度均为1;

15!!=1*3*5*7*9*11*13*15,.....19!!=1*3*5*7*9*11*13*15*17*19,这5个数贡献度均为2

比如说当n为31时,每5个数贡献度+1,所以我们就算出这些数的贡献度,即5个1,5个2,4个3,如何算呢?可以先算出整个区间的长度,len=(n+1)/2-(i+1)/2+1;其中n为31,(n+1)/2即代表31!!所在的下标,i表示每几个数贡献度+1,此时等于5,(i+1)/2表示5!!的下标,两下标相减再加1即表示区间长度,然后以每5个数为一个周期区间,算出n所在的周期区间不算,然后前面有几个完整的周期区间,maxn=(len-1)/i,然后len*(maxn+1)-i*maxn*(maxn+1)/2就是用len*3减去一个等差数列求和,得到每5个数加1得到的所有数的贡献度

但是,这样还远远不够,因为我们发现25的贡献度并不只是3,25=1*3*5*7*9*11*13*15*17*19*21*23*25,发现贡献度为4,它是在贡献度为3的基础上加了1,也就是说每25个数,它会在原来贡献度的基础上再加个1 

然后同理,每125个数,它会在原来贡献度的基础上再加个1,以此类推,5的幂次... 

所以总结下来就是:每5个数贡献度加1,每25个数贡献度加2,每125个数贡献度加3...,但由于算每5个数贡献度加1的时候已经给25和125加1了,所以算每25个数也是贡献度加1,由于算25个数贡献度也给125加1了,所以算每125个数也是贡献度加1,以此类推... 

对于偶数,同理,我们会发现,从10开始,即10!!,12!!,14!!,....

也是每5个数贡献度加1,每25个数贡献度加2...

所以同理,只需在i的基础上乘2,再以同样的方法算贡献度即可

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
#define int __int128
using namespace std;
typedef long long ll;
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}
inline void print(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9){
        print(x/10);
    }
    putchar(x%10+'0');
}
int n;
void solve()
{
    n=read();
    int res=0;
    for(int i=5;i<=n;i*=5){
        
        int len=(n+1)/2-(i+1)/2+1;
        int maxn=(len-1)/i;
        res+=len*(maxn+1)-i*maxn*(maxn+1)/2;
        
        int j=i*2;
        if(j>n) break;
        len=n/2-j/2+1;
        maxn=(len-1)/i;
        res+=len*(maxn+1)-i*maxn*(maxn+1)/2;
    }
    print(res);
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--)
        solve();
    return 0;
}

E.sequence

大致题意是能否把区间[l,r]分成k段,使得每一段的和均为偶数(有q次询问)

我们需要先预处理每个区间最多能分成几段区间保证区间和均为偶数

法一:

如果是偶数的话,完全可以自己作为一段区间,但是如果遇到奇数的话,就得至少到下一个奇数,这一整段作为一个区间

这里我们考虑奇数个数前缀和以及偶数个数前缀和

如上图,区间的分法一共有两种

一种是从第一个奇数到第二个奇数作为一个区间,第三个奇数到第四个奇数作为一个区间,..,未包含在以上区间的每个偶数单独作为一个区间,用数组x来单独处理第一种分法的有效偶数个数前缀和(具体操作是,先将有效的偶数记为1,再跑一遍前缀和)

另一种是从第二个奇数到第三个奇数作为一个区间,从第四个奇数到第五个奇数作为一个区间,...,未包含在以上区间的每个偶数单独作为一个区间,用数组y来单独处理第二种分法的有效偶数个数前缀和(具体操作是,先将有效的偶数记为1,再跑一遍前缀和)

只有这两种预处理能使得区间分的段数最多

然后再预处理一遍奇数个数前缀和

然后就是q次询问,对于每一个区间[l,r],如果奇数个数为奇数,那么不可能分成都是偶数和的k段,return no

如果区间长度小于k,return no

然后看区间[l,r]前面有即个奇数,即z[l-1],如果前面奇数的个数是奇数,我们就采用第二种分法,否则就采用第一种分法(从图中很容易看出)

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<deque>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1e5+10;
const string yes="YES",no="NO";
ll a[N];
int x[N],y[N],z[N];
int n,q;
string query() {
    int l,r,k;
    cin>>l>>r>>k;
    if((z[r]-z[l-1])%2==1||r-l+1<k) return no;
    if(z[l-1]%2==1) {
        ll res=(z[r]-z[l-1])/2+y[r]-y[l-1];
        if(k<=res) return yes;
    } else {
        ll res=(z[r]-z[l-1])/2+x[r]-x[l-1];
        if(k<=res) return yes;
    }
    return no;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--) {
        cin>>n>>q;
        for(int i=1; i<=n; i++) cin>>a[i];
        for(int i=1;i<=n;i++) x[i]=y[i]=0;
        //预处理奇数个数前缀和
        for(int i=1; i<=n; i++) {
            z[i]=z[i-1];
            if(a[i]%2==1) z[i]++;
        }
//        for(int i=1;i<=n;i++) cout<<z[i]<<" ";
//        cout<<endl;
        int flag=1;
        for(int i=1; i<=n; i++) {
            if(a[i]%2==1) {
                flag=1-flag;
                continue;
            }
            if(a[i]%2==0&&flag==0) y[i]=1;
            else if(a[i]%2==0&&flag==1) x[i]=1;
        }
        //预处理偶数前缀和个数
        for(int i=2; i<=n; i++) x[i]+=x[i-1],y[i]+=y[i-1];
//        for(int i=1;i<=n;i++) cout<<x[i]<<" ";
//        cout<<endl;
//        for(int i=1;i<=n;i++) cout<<y[i]<<" ";
//        cout<<endl;
//        for(int i=1;i<=n;i++) cout<<z[i]<<" ";
//        cout<<endl;
        while(q--) cout<<query()<<endl;
    }
    return 0;
}

法二:

用数组b记录前缀和,用数组c记录每一个位置已经有多少个偶区间了

同法一,如果该区间前面偶区间的个数为偶数,那么就选择第一种选法,否则就选择第二种选法

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const string yes="YES",no="NO";
const int N=1e5+10;
ll a[N];
int n,q;
ll b[N],c[N];
string query(){
    ll l,r,k;
    cin>>l>>r>>k;
    if(r-l+1<k) return no;
    if((b[r]-b[l-1])%2==1) return no;
    if(b[l-1]%2==0){
        if(c[r]-c[l-1]>=k) return yes;
    }
    else{
        if(r-l+1-(c[r]-c[l-1])>=k) return yes;
    }
    return no;
}
void solve()
{
    cin>>n>>q;
    for(ll i = 1; i <= n; i ++ ) {
        cin >> a[i];
        b[i] = a[i] + b[i - 1];
        if(b[i] % 2 == 0) c[i] = c[i - 1] + 1;
        else c[i] = c[i - 1];
    }
    while(q--){
        cout<<query()<<endl;
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

G.Gcd

可以将a-b插入集合中,然后会不断地将集合中的两个数拿出来相减,再放回集合中,这让我想到了辗转相减法,是为了求两个数的最大公约数的

关于数学的题目,就用数学去推式子

有d=gcd(a,b)

假设a=k1*d,b=k2*d,a-b=(k1-k2)*d,得到的是d的倍数,之后每次取出两个数相减,也都是可以提取公因数d的,得到的始终是d的倍数,也就是说我们只能得到gcd(a,b)的倍数(可以用正数减负数得到更大的数)

然后对z为0时特判,题目说不能操作两个一样的数,所以当z为0时,a,b至少一个为0才可以

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<cstdio>
#define endl '\n'
#define int long long
using namespace std;
typedef long long ll;
int x,y,z;
const string yes="YES";
const string no="NO";
int gcd(int a,int b){
    if(b==0) return a;
    return gcd(b,a%b);
}
string solve(){
    cin>>x>>y>>z;
    if(x==z||y==z) return yes;
    if(z==0) return no;
    int d=gcd(x,y);
    if(z%d==0) return yes;
    return no;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
        cout<<solve()<<endl;
    return 0;
}

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

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

相关文章

【力扣每日一题】2023.8.8 任意子数组和的绝对值的最大值

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个数组&#xff0c;让我们找出它的绝对值最大的子数组的和。 这边的子数组是要求连续的&#xff0c;让我们找出一个元素之和…

Cadvisor+InfluxDB+Grafan+Prometheus(详解)

目录 一、CadvisorInfluxDBGrafan案例概述 &#xff08;一&#xff09;Cadvisor Cadvisor 产品特点&#xff1a; &#xff08;二&#xff09;InfluxDB InfluxDB应用场景&#xff1a; InfluxDB主要功能&#xff1a; InfluxDB主要特点&#xff1a; &#xff08;三&#…

【mock安装时报错】

node版本需要大于16 切换>16的版本即可 建议使用 nvm进行 node版本状态管理 可参考另一篇文章 nvm多版本管理方案

2021年09月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 取整除的运算符是? A:/ B:// C: D:** 正确的答案是:B://。 解析:在Python中,取整除的运算符是双斜杠(//)。它执行除法运算并返回结果的整数部分,即向下取整。相比之下,除法运算符(/)返回的是精确的浮点数结…

C语言数组第十课---------------三子棋-------数组经典练手题

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; &#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382;…

从0到1搭建uniapp

一、什么是uniapp UniApp是一款基于Vue.js框架的全端开发工具&#xff0c;可以实现同时开发多个平台&#xff08;包括H5、小程序、APP等&#xff09;应用的能力。使用UniApp&#xff0c;开发者只需要编写一份代码就可以快速地发布到多个平台&#xff0c;极大地提高了开发效率和…

java实现当前系统时间格式化

import java.text.SimpleDateFormat; import java.util.Date;public class DateTest {public static void main(String[] args) {Date date new Date();System.out.println("当前系统时间&#xff1a;" date);SimpleDateFormat simpleDateFormat new SimpleDateFo…

MySQL 查询语句大全

目录 基础查询 直接查询 AS起别名 去重&#xff08;复&#xff09;查询 条件查询 算术运算符查询 逻辑运算符查询 正则表达式查询⭐ 模糊查询 范围查询 是否非空判断查询 排序查询 限制查询&#xff08;分页查询&#xff09; 随机查询 分组查询 HAVING 高级查询…

数据结构和算法三(排序)

列表排序 排序类型&#xff1a; 一、冒泡排序&#xff1a; 屏幕录制2023-07-25 13.05.12 def bubble_sort(li):exchangeFalseif len(li)<1:return lifor i in range(len(li)-1):for j in range(len(li)-i-1):if li[j]>li[j1]:li[j],li[j1]li[j1],li[j]print(li)exchangeT…

【数理知识】奇异值分解,从数据的线性变换角度来理解

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

学习电气工程的关键要点

基础知识&#xff1a;学习电路原理、电子器件、电机原理等基础知识。可以通过自学、培训或相关专业课程来学习。 编程技能&#xff1a;掌握一门编程语言&#xff0c;如C语言或MATLAB。电气工程常需要编程来设计和实现控制系统。 自动化控制理论&#xff1a;了解自动化控制系…

Python web实战之Django 的 RESTful API 设计详解

关键词: Python, Web 开发, Django, RESTful API 1 API的一些事儿 1.1 什么是API&#xff1f; API是应用程序编程接口&#xff08;Application Programming Interface&#xff09;的缩写。它是一种定义了不同软件组件之间交互方式的规范。API允许不同的应用程序之间进行通信和…

【LeetCode】数据结构题解(10)[有效的括号]

有效的括号 &#x1f609; 1.题目来源&#x1f440;2.题目描述&#x1f914;3.解题思路&#x1f973;4.代码展示 &#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1f618;&#x1…

机器学习笔记:李宏毅ChatGPT Finetune VS Prompt

1 两种大语言模型&#xff1a;GPT VS BERT 2 对于大语言模型的两种不同期待 2.1 “专才” 2.1.1 成为专才的好处 Is ChatGPT A Good Translator? A Preliminary Study 2023 Arxiv 箭头方向指的是从哪个方向往哪个方向翻译 表格里面的数值越大表示翻译的越好 可以发现专门做翻…

vue3 table动态合并,自定义参数合并单元格

<template><div><el-table :data"tableData" :span-method"objectSpanMethod" border:header-cell-style"{ textAlign: center}"><el-table-column prop"area" label"区域" align"center"&g…

如何在页面中嵌入音频和视频?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 嵌入音频⭐ 嵌入视频⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏…

《合成孔径雷达成像算法与实现》Figure3.2

代码参数说明&#xff1a;Sf1为书中公式3.19&#xff0c;Sf2为时域信号快速傅里叶表达式&#xff0c;两种频谱表达式所做出的图可看出其区别 代码如下&#xff1a; clc clear all close all%参数设置 TBP 720; %时间带宽积 T 10e-6; %脉冲持续时间%参数计…

20.5 HTML 媒体

1. video视频标签 video视频标签: 是HTML中用于在网页上嵌入视频的元素.常用的视频标签属性: - src属性: 指定视频文件的URL地址. - controls属性: 用于显示视频播放控件(如播放按钮, 进度条等), 使用户能够控制视频的播放. - width和height: 指定视频的宽度和高度. - autopla…

ESP32 Max30102 (3)修复心率误差

1. 运行效果 2. 新建修复心率误差.py 代码如下: from machine import sleep, SoftI2C, Pin, Timer from utime import ticks_diff, ticks_us from max30102 import MAX30102, MAX30105_PULSE_AMP_MEDIUM from hrcalc import calc_hr_and_spo2BEATS = 0 # 存储心率 FINGER_F…

MATLAB详细安装教程(亲测有效!!)

1.复制以下链接&#xff0c;用百度网盘打开&#xff0c;下载 链接&#xff1a;https://pan.baidu.com/s/19AwQeCRYofGAV8sfDIm5PQ 提取码&#xff1a;mads 我是下载到D盘自己创建的文件中 2.下载完毕后打开此文件夹&#xff0c;点击最后一项 3.点击右上角高级选项&#xff0…