华华给月月出题
题目描述
B-华华给月月出题_牛客竞赛数学专题班积性函数(积性函数概念、欧拉筛求积性函数、莫比乌斯反演) (nowcoder.com)
运行代码
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1.3e7+7;
const int mod=1e9+7;
int prime[N],cnt,vis[N];
int FM(int m,int k,int p){
int res=1,a=m%p;
while(k){
if(k&1)res=(ll)res*a%p;
a=(ll)a*a%p;
k>>=1;
}
return res;
}
void init(int n){
vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[cnt++]=i;
vis[i]=FM(i,n,mod);
}
for(int j=0;prime[j]<=n/i;j++){
vis[i*prime[j]]=(ll)vis[i]*vis[prime[j]]%mod;
if(i%prime[j]==0)break;
}
}
}
int main(){
int n;
cin>>n;
init(n);
ll ans=0;
for(int i=1;i<=n;i++){
ans^=vis[i];
}
cout<<ans<<endl;
return 0;
}
代码思路
-
定义了一些常量和数组:
N
表示一个较大的上限。mod
用于取模运算。prime
数组用于存储质数,cnt
用于记录质数的个数,vis
数组用于存储一些计算结果。
-
定义了一个函数
FM
用于快速幂运算,计算m
的k
次幂对p
取模的结果。 -
init
函数用于初始化vis
数组:- 从 2 到
n
遍历,如果一个数i
未被标记(即不是之前找到的质数的倍数),则将其标记为质数,并计算i
的n
次幂对mod
取模的结果存储在vis[i]
中。 - 对于每个数
i
,再遍历之前找到的质数,如果i
是某个质数的倍数,则计算并更新vis[i * prime[j]]
,如果i
恰好是某个质数的倍数,就提前退出内层循环。
- 从 2 到
-
在
main
函数中:- 读取输入的整数
n
。 - 调用
init
函数进行初始化。 - 计算
vis
数组中从 1 到n
的元素的异或和,存储在ans
中。 - 输出
ans
的值。
- 读取输入的整数
B. 数因式分解
题目描述
运行代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int, int>> a;
int x = 1;
void cal(int n) {
for (int i = 2; i * i <= n; i++) {
bool flag = false;
int cnt = 0;
while (n % i == 0) {
cnt++;
n /= i;
flag = true;
}
if (flag) {
x *= i;
a.emplace_back(cnt, i);
}
if (n == 1) {
return;
}
}
if (n > 1) {
a.emplace_back(1, n);
x *= n;
}
}
int main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
x = 1;
a.clear();
int n;
cin >> n;
cal(n);
sort(a.begin(), a.end());
int ans = 0;
int mi = 0;
for (const auto& p : a) {
ans += x * (p.first - mi);
mi = p.first;
x /= p.second;
if (x == 1) {
break;
}
}
cout << ans << endl;
}
return 0;
}
代码思路
-
cal
函数:- 这个函数用于对给定的整数
n
进行质因数分解。 - 从 2 开始到
sqrt(n)
遍历,检查每个数是否能整除n
。 - 如果能整除,就记录该数的出现次数
cnt
,并标记为一个质因数(flag = true
)。 - 每次整除后更新
n
的值,并在质因数确定时将其相关信息(出现次数和本身的值)存入a
向量,并更新x
的值(x
记录所有不同质因数的乘积)。 - 如果在遍历完
sqrt(n)
后n
仍大于 1,说明还有一个大于sqrt(n)
的质因数,也将其存入a
向量并更新x
。
- 这个函数用于对给定的整数
-
main
函数:- 首先进行一些输入输出流的设置,以提高效率。
- 读入测试用例的数量
t
。 - 在每次测试用例中:
- 初始化
x
为 1 ,并清空a
向量。 - 读入要分解的整数
n
,调用cal
函数进行质因数分解。 - 对
a
向量按照指数(即pair
的第一个元素)进行排序。 - 计算答案
ans
:通过遍历a
向量,根据当前质因数的指数与之前已记录的指数mi
的差值,乘以x
的值来累计答案,并更新mi
和x
。如果x
变为 1 则提前结束循环。 - 输出本次测试用例的答案。
- 初始化
来点gcd
题目描述
运行代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n,m,x,h[N];
int main(){
int t;
scanf("%d",&t);
while(t--){
for(int i=0;i<=n;i++) h[i]=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&x);
h[x]++;
}
while(m--){
scanf("%d",&x);
int p=0;
for(int i=x;i<=n&&p!=x;i+=x){
if(h[i]) p=__gcd(i,p);
}
if(p==x) puts("YES");
else puts("NO");
}
}
return 0;
}
代码思路
- 定义了一个
gcd
函数来计算两个数的最大公约数。 - 在主函数中,首先读入测试用例的数量
t
。 - 对于每个测试用例,先初始化
h
数组,然后读入两个整数n
和m
,并记录数字的出现次数。 - 对于
m
次询问,通过循环计算与给定数字x
相关的最大公约数,并根据结果输出相应的结果。