当前位置: 首页 > news >正文

河南萌新联赛2025第(二)场:河南农业大学(补题)

文章目录

  • 前言
  • A.约数个数和
    • 整除分块(相当于约数求和)
      • 相关例题:取模
  • B.异或期望的秘密
    • 二进制的规律
      • 相关例题
        • 累加器
        • 小蓝的二进制询问
    • 乘法逆元
      • 1. 概念
      • 2.基本定义
      • 3.费马小定理
        • 1.定理内容
        • 2.重要推论
  • D.开罗尔网络的备用连接方案
  • E.咕咕嘎嘎!!!(easy)
  • I.猜数游戏(easy)
  • K.打瓦
  • M.米娅逃离断头台
  • 总结

前言

依旧是只会写签到题的一场。


A.约数个数和

题目传送门:约数个数和
在这里插入图片描述
这一题利用到了整除分块,如果不这样的话,数据太大,会时间超限。
AC代码:

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
ll ans=0;
void solve()
{ll n;cin>>n;for(ll l=1,r;l<=n;l=r+1){r=n/(n/l);ans+=(n/l)*(r-l+1);}cout<<ans<<endl;
}
signed main()
{IOS;ll t=1;//cin>>t;while(t--)solve();return 0;}

整除分块(相当于约数求和)

介绍:整除分块(也叫数论分块)是数论和算法竞赛中常用的优化技巧,主要用于高效计算形如
∑i=1nf(i)⋅g(⌊ni⌋)\sum_{i=1}^n f(i) \cdot g\left(\left\lfloor \frac{n}{i} \right\rfloor\right) i=1nf(i)g(in) 的求和式,核心思想是利用「整除的周期性」,将求和式中结果相同的区间合并,减少计算次数。
一、整除分块的核心原理
利用整除的「周期性」对于固定的 n,当 i 从 1 到 n 变化时,⌊ni⌋\left\lfloor \frac{n}{i} \right\rfloorin 的值会分段相同。
例如:(n=10) 时,⌊10i⌋\left\lfloor \frac{10}{i} \right\rfloori10 的取值如下:
i12345678910(\left\lfloor \frac{10}{i} \right\rfloor)10532211111
可以看到,⌊ni⌋\left\lfloor \frac{n}{i} \right\rfloorin 的值会形成连续的区间段(如 i=4,5 时,值都是 2;i=6∼10i=6\sim10 i=610时,值都是 1)。关键发现:
对于某个值 k=⌊ni⌋k = \left\lfloor \frac{n}{i} \right\rfloork=in,所有能使 ⌊ni⌋=k\left\lfloor \frac{n}{i} \right\rfloor = kin=k的 i 会构成一个连续区间 ([l, r]),其中:左端点 l 是当前区间的起始右端点 r 满足:
r=⌊nk⌋=⌊n⌊nl⌋⌋r = \left\lfloor \frac{n}{k} \right\rfloor = \left\lfloor \frac{n}{\left\lfloor \frac{n}{l} \right\rfloor} \right\rfloorr=kn=lnn
利用这一性质,我们可以将原本需要遍历 n 次的求和,优化为遍历所有不同的 k 对应的区间段,时间复杂度从O(n)降到O(n)(因为不同的k最多有2n个)时间复杂度从 O(n) 降到 O(\sqrt{n})(因为不同的 k 最多有 2\sqrt{n} 个)时间复杂度从O(n)降到O(n)(因为不同的k最多有2n个)
模板

long long sum = 0;
for (int l = 1, r; l <= n; l = r + 1) {int k = n / l;r = n / k;  // 计算当前段的右端点sum += (r - l + 1) * k;
}

相关例题:取模

题目传送门:取模
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于这一题,同样可以通过一系列推理,将其转换到整除分块
利用取模的数学定义:
n%i=n−i⋅⌊ni⌋n \% i = n - i \cdot \left\lfloor \frac{n}{i} \right\rfloorn%i=niin因此,原求和式可展开为:
∑i=1n(n%i)=∑i=1n(n−i⋅⌊ni⌋)\sum_{i=1}^n \left( n \% i \right) = \sum_{i=1}^n \left( n - i \cdot \left\lfloor \frac{n}{i} \right\rfloor \right)i=1n(n%i)=i=1n(niin)拆分求和式:
∑i=1n(n%i)=∑i=1nn−∑i=1n(i⋅⌊ni⌋)\sum_{i=1}^n \left( n \% i \right) = \sum_{i=1}^n n - \sum_{i=1}^n \left( i \cdot \left\lfloor \frac{n}{i} \right\rfloor \right)i=1n(n%i)=i=1nni=1n(iin)
对于i求和,可以通过等差数列求和推理出来
AC代码:

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
const ll mod=998244353;
void solve()
{ll n;cin>>n;__int128 ans=0;//特别注意类型,因为数据范围非常大for(__int128 l=1,r;l<=n;l=r+1){ll k=n/l;r=n/k;ans+=k*((r-l+1)*(r-l)/2+(r-l+1)*l)%mod;}ll an=((__int128)n*(__int128)n-ans)%mod;cout<<an<<endl;
}
signed main()
{IOS;ll t=1;// cin>>t;while(t--)solve();return 0;
}

B.异或期望的秘密

题目传送门:异或期望的秘密
在这里插入图片描述
这一题用到的知识就很多了,有关于二进制的规律,以及乘法逆元,还有数学期望的计算;
思路:
通过数据范围可以发现,直接进行循环肯定会时间超限,为此就有了一个很妙的方法,利用到异或以及二进制的规律,通过遍历y在bitset的每一位,通过当前y在二进制下的0与1,与L到R之间相同位数下的1的个数来进行判断,由于异或的性质,相同为0,由此来反着推出贡献为1的总数,最后再通过乘法逆元。
AC代码:

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
const ll mod=1e9+7;
ll qmod(ll x,ll y)//乘法逆元(快速幂)
{ll sum=1;while(y){if(y&1){sum*=x;sum%=mod;}x*=x;x%=mod;y>>=1;}return sum;
}
ll f(ll x,ll i)//计算x第i位的1的个数
{if(x==0)return 0;ll sum=0;ll val=1ll<<i;//每个周期的贡献值ll curr=1ll<<(i+1);//一个周期的大小ll re=x%curr-val+1;//计算不足一个周期的贡献值sum+=val*(x/curr);//计算整周期的贡献sum+= max((ll)0,re);//比较剩余周期是否有贡献值sum%=mod;return sum;
}
void solve()
{ll l,r,y;cin>>l>>r>>y;ll k=r-l+1;ll ans=0;bitset<31>m(y);//方便进行异或for(ll i=0;i<=29;i++){ll num=f(r,i)-f(l-1,i);//计算当前位数的区间1的个数总和if(m[i]==1)num=k-num;//贡献为0的反推出贡献为1的ans+=num;ans%=mod;}cout<<(ans*qmod(k,mod-2))%mod<<endl;//乘法逆元
}
signed main()
{IOS;ll t=1;cin>>t;while(t--)solve();return 0;
}

二进制的规律

1 —— 00001
2 —— 00010
3 —— 00011
4 —— 00100
5 —— 00101
6 —— 00110
7 —— 00111
8 —— 01000
9 —— 01001
10 ——01010
11 —— 01011
12 —— 01100
13 —— 01101
14 —— 01110
15 —— 01111
16 —— 10000
17 —— 10001
18 —— 10010
19 —— 10011
20 —— 10100
通过观察会发现,每一位的周期就是权值的2倍,而权值又是该当前位数的
(2i ),注意位数i是从0开始的,故而周期为2i+1 .
至于求余数的贡献值时,会发现在周期的一半的前一位值是1,故而需要多加上1,因为其是余数减去一半的周期。
关键点:

    if(x==0)return 0;ll sum=0;ll val=1ll<<i;//每个周期的贡献值ll curr=1ll<<(i+1);//一个周期的大小ll re=x%curr-val+1;//计算不足一个周期的贡献值sum+=val*(x/curr);//计算整周期的贡献sum+= max((ll)0,re);//比较剩余周期是否有贡献值

相关例题

累加器

题目传送门:累加器
在这里插入图片描述
在这里插入图片描述
通过观察样例会发现,每位改变的位数,都与当前的2的位数次方
AC代码;

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define pii pair<ll,ll>
const ll N=1e6+10;
ll f(ll x)//进行前缀和
{ll sum=0;ll y=log2(x);for(ll i=0;i<y;i++){ll k=(ll)pow(2,i);//关键规律sum+=x/k;}return sum;
}
void solve()
{ll x,y;cin>>x>>y;cout<<f(x+y)-f(x)<<endl;
}
signed main()
{IOS;ll t=1;cin>>t;while(t--)solve();return 0;
}
小蓝的二进制询问

题目传送门:小蓝的二进制询问

在这里插入图片描述
这一题便是之前的规律了;
AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
#define pii pair<ll,ll>
const ll N=1e6+10;
const ll mod=998244353;
ll f(ll x)
{ll sum=0;ll y=log2(x)+1;//计算当前的位数if(x==0)return 0;ll val=1;for(ll i=0;i<=y;i++){val=1ll<<i;//权值ll curr=val*2;//周期sum+=val*(x/curr);//完整周期总和ll re=x%curr-val+1;//剩余周期的贡献sum+=max((ll)0,re);//判断是否有贡献sum%=mod;}return sum%mod;
}
void solve()
{ll x,y;cin>>x>>y;cout<<(f(y)-f(x-1)+mod)%mod<<endl;
}
signed main()
{IOS;ll t=1;cin>>t;while(t--)solve();return 0;
}

乘法逆元

1. 概念

在数学中,乘法逆元是一个与乘法运算相关的重要概念,它描述了两个数之间的一种特殊关系。简单来说,对于给定的数 a,如果存在另一个数 b,使得它们的乘积等于乘法单位元(通常是 1),那么 b 就被称为 a 的乘法逆元。

2.基本定义

设 a 是一个数(或更广泛的代数结构中的元素),若存在数 b 满足:a×b=b×a=1a \times b = b \times a = 1a×b=b×a=1
则称 b 是 a 的乘法逆元,记作 b=a−1b = a^{-1}b=a1(读作 “a 的逆”)。这里的 “1” 是乘法单位元,即与任何数相乘都不改变该数的特殊元素(例如整数乘法中,1 就是单位元)。

3.费马小定理

1.定理内容

若 p 是一个质数,且整数 a 不是 p 的倍数(即a与p互质,gcd⁡(a,p)=1)(即 a 与 p 互质,\gcd(a, p) = 1)(即ap互质,gcd(a,p)=1)
则有:ap−1≡1(modp)a^{p-1} \equiv 1 \pmod{p}ap11(modp)
符号解释:≡(modp)表示“模p同余”,即ap−1除以p的余数等于1。\equiv \pmod{p}表示 “模 p 同余”,即 a^{p-1}除以 p 的余数等于 1。(modp)表示p同余,即ap1除以p的余数等于1

2.重要推论

费马小定理的一个关键应用是求模运算中的乘法逆元。
由定理 ap−1≡1(modp)a^{p-1} \equiv 1 \pmod{p}ap11(modp)
变形可得:a×ap−2≡1(modp)a \times a^{p-2} \equiv 1 \pmod{p}a×ap21(modp)
这表明:当 p 是质数且 a 与 p 互质时,ap−2modpa^{p-2} \mod pap2modp
就是 a 模 p 的乘法逆元(即a−1≡ap−2(modp))(即 a^{-1} \equiv a^{p-2} \pmod{p})(即a1ap2(modp)

根据费马小定理,当 p 是质数且 gcd⁡(a,p)=1时\gcd(a, p) = 1时gcd(a,p)=1
有:ap−1≡1(modp)a^{p-1} \equiv 1 \pmod{p}ap11(modp)
将等式左边因式分解(把ap−1拆成a×ap−2),得到:a×ap−2≡1(modp)(把 a^{p-1} 拆成 a \times a^{p-2} ),得到:a \times a^{p-2} \equiv 1 \pmod{p}(把ap1拆成a×ap2),得到:a×ap21(modp)

D.开罗尔网络的备用连接方案

题目传送门:开罗尔网络的备用连接方案
在这里插入图片描述
在这里插入图片描述
通过题目,可以发现就是一个加权无向图,来求取经过按位与之后该数二进制下1的个数,

AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e5+10;
vector<ll> p[N];//用来存边
ll a[N];//存该节点的权值
ll ans[N];//保存种类数目
void dfs(ll x,ll w,ll f)
{ll c=a[x]&w;//每次都进行按位与bitset<40>b(c);//为了更好的求1的个数ans[b.count()]++;//统计种类for(ll i:p[x]){if(i!=f)//防止重边也就是防止一个节点遍历两次{dfs(i,c,x);//继续往下搜索i代表的是子节点,c则是要更新的值,x则代表的是父节点}}
}
void solve()
{ll n,q;cin>>n>>q;for(ll i =1;i<=n;i++)cin>>a[i];for(ll i=1;i<n;i++){ll x,y;cin>>x>>y;p[x].push_back(y);//存边,即双向边p[y].push_back(x);}dfs(1,-1,0);//从节点1开始进行搜索while(q--){ll x;cin>>x;cout<<ans[x]<<endl;}
}
signed main()
{IOS;ll t=1;//cin>>t;while(t--)solve();return 0;
}

E.咕咕嘎嘎!!!(easy)

题目传送门:咕咕嘎嘎!!!(easy)
在这里插入图片描述
在这里插入图片描述
对于这一题,既然最大公因数为1的不满足,那就求出最大公因数大于等于2的。

一、问题转化:补集思想 + 容斥原理
题目要求 选 m 个石头,且它们的 gcd 不为 1 的方案数。直接计算较复杂,采用 补集思想 + 容斥原理 转化问题:
补集思想
总合法方案 = 所有 gcd 为 d(d≥2)的方案数之和。
但直接枚举 d 会重复计算(比如 gcd 为 6 的方案会被 d=2 和 d=3 重复统计),因此需要容斥:从大到小枚举 d,减去其倍数的贡献。
容斥原理
定义 f[d] 为选 m 个石头、且它们的 gcd 恰好为 d 的方案数。
但直接求 f[d] 困难,因此先定义 g[d] 为选 m 个石头、且它们的 gcd 是 d 的倍数(即所有选中的数都是 d 的倍数)的方案数。
则根据容斥关系:f[d]=g[d]−∑k>d,d∣kf[k]f[d] = g[d] - \sum_{k > d,\ d|k} f[k]f[d]=g[d]k>d, dkf[k]
通过从大到小枚举 d,用 f[d] -= f[k] 的方式实现容斥。
二,预处理:求组合数
递推:s[i][j] = s[i-1][j-1] + s[i-1][j](选第 i 个元素则从 i-1 选 j-1,不选则从 i-1 选 j)。
这样可以在 O(n^2) 时间内预处理出所有需要的组合数,避免重复计算。
三,核心流程
1. 计算 g[d]:选 m 个 d 的倍数的方案数
对于每个 d(从 1 到 n):
统计 1~n 中是 d 的倍数的数的个数,记为 num = n / d(因为 d, 2d, 3d, …, kd ≤n → k = n/d)。
若 num ≥ m,则从 num 个数中选 m 个的方案数为组合数 s[num][m],即 g[d] = s[num][m];否则 g[d] = 0(不够选 m 个)。

for(ll i=1;i<=n;i++){ll num=n/i;if(num>=m)f[i]=s[num][m];elsef[i]=0;}

2. 容斥修正:从大到小枚举 d
为了得到恰好 gcd 为 d 的方案数 f[d],需要减去所有 d 的倍数 k=2d, 3d, … 的 f[k]:

for(ll i=n;i>=2;i--) {for(ll j=2*i;j<=n;j+=i) {f[i] = (f[i] - f[j] + mod) % mod;}ans = (ans + f[i] + mod) % mod;
}

从大到小枚举:保证处理 d 时,其倍数 k>d 已经被处理过,这样减去的 f[k] 是 “恰好 gcd 为 k” 的方案数,避免重复计算。
(f[i] - f[j] + mod) % mod:防止负数,用 mod 调整。
AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=5e3+10;
const ll mod=1e9+7;
ll s[N][N];
ll f[N];
void pre()//预处理组合数
{for(ll i=0;i<=N;i++){s[i][0]=0;s[i][i]=1;for(ll j=0;j<i;j++){s[i][j]=(s[i-1][j-1]+s[i-1][j]+mod)%mod;}}
}
void slove()
{ll n,m;cin>>n>>m;ll ans=0;for(ll i=1;i<=n;i++){ll num=n/i;//1~n中i的倍数的个数if(num>=m)// 若数量足够选m个f[i]=s[num][m];elsef[i]=0;}// 第二步:容斥原理计算f[d] = 选m个数且gcd恰好为d的方案数// 从大到小枚举d,确保处理d时其倍数已被处理for(ll i=n;i>=2;i--){// 减去所有i的倍数的f[j](这些是gcd为j的方案,已被包含在g[i]中)for(ll j=2*i;j<=n;j+=i){f[i]=(f[i]-f[j]+mod)%mod;}// 累加所有gcd≥2的方案数ans=(ans+f[i]+mod)%mod;}cout<<ans<<endl;
}
signed main()
{IOS;ll t=1;pre();// cin>>t;while(t--)slove();return 0;
}

I.猜数游戏(easy)

题目传送门:猜数游戏(easy)
在这里插入图片描述
签到题没啥说的
AC代码:

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
ll ans=0;
void solve()
{ll n;cin>>n;ll sum=1;while(sum<=n){sum*=2;ans++;}if(sum/2==n)cout<<ans-1<<endl;elsecout<<ans<<endl;
}
signed main()
{IOS;ll t=1;//cin>>t;while(t--)solve();return 0;}

K.打瓦

题目传送门:打瓦
在这里插入图片描述
同样签到题
AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
void solve()
{string s;cin>>s;cout<<"gugugaga"<<endl;
}
signed main()
{IOS;ll t=1;//cin>>t;while(t--)solve();return 0;}

M.米娅逃离断头台

题目传送门:米娅逃离断头台

在这里插入图片描述
简单的数学题
AC代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
#define endl '\n'
const ll N=1e6+10;
double x;
void solve()
{cin>>x;double sum=3.1415926535;double ans=0;if(x==0){printf("0.00\n");return ;}else{ans=(sum*x*x)/8;printf("%.2lf\n",ans);}
}
signed main()
{IOS;ll t=1;//cin>>t;while(t--)solve();return 0;}

总结

对于其他题,尤其a题就是属于没思路的一题
而D题,才开始题目没看太懂,没有建立无向边,建立的是有向边,等到后续给了题目更近一步的解释时,越来越迷糊,图论还是接触的少。

http://www.dtcms.com/a/305122.html

相关文章:

  • 高端医疗超声AFE模拟前端应用
  • 机器学习之线性回归——小白教学
  • 关于为什么写分配法搭配写回法?非写分配法搭配全写法?
  • python基础:request请求查询参数的基本使用、携带请求参数的两种方法、 json串和python中数据类型转化、 post模拟登录
  • 全方位Python学习方法论:从入门到精通的系统指南
  • GB/T 4706.1-2024 家用和类似用途电器的安全 第1部分:通用要求 与2005版差异(21)
  • 【Spring】日志级别的分类和使用
  • 计算机视觉-局部图像描述子
  • 代理IP轮换机制:突破反爬虫的关键策略
  • AI驱动的知识管理新时代:释放组织潜力的关键武器
  • win10 环境删除文件提示文件被使用无法删除怎么办?
  • MPLS 专线网络
  • 字符集学习
  • 实现多路标注截图
  • GESP2025年6月认证C++七级( 第三部分编程题(1)线图)
  • Spring Boot中的this::语法糖详解
  • Spring与数学的完美碰撞
  • 偏二甲肼气体浓度报警控制系统
  • 自适应双门限的能量检测算法
  • Python算法实战:从排序到B+树全解析
  • TDengine:用AI改变数据消费范式
  • linux命令ps的实际应用
  • 学习Python中Selenium模块的基本用法(3:下载浏览器驱动续)
  • 微服务快速入门
  • BehaviorTree.Ros2 编译教程
  • JavaWeb 入门:JavaScript 基础与实战详解(Java 开发者视角)
  • 飞算科技:以原创之力,开启Java开发新纪元与行业数智变革
  • 技术QA | GNSS模拟器如何赋能自动驾驶?聚焦HIL、多实例与精准轨迹仿真的技术优势
  • Ignite(Apache Ignite)中计算与数据共置的核心概念和编程实践
  • 小程序视频播放,与父视图一致等样式设置