2024.9.29校测

T1

题目描述

Mr.Hu 最近偶得一函数:

f(n)=(dnφ(d))m(dnσ0(d)μ(nd)nd)

其中 σ0(n) 表示 n 的正约数个数,比如 σ0(12)=6,因为 121,2,3,4,6,126 个正约数。

其中 φ(n) 是欧拉函数,μ(n) 是莫比乌斯函数。

又有:F(n)=i=1nf(i)

Mr.Hu 希望你计算 F(n)mod109+7 的值。

输入格式

第一行包含两个整数:n,m

输出格式

输出一行包含一个数,表示答案。

输入样例

3 1

输出样例

1000000005

样例解释

f(1)=1,f(2)=0,f(3)=3,故 F(3)=f(1)+f(2)+f(3)=2,在模意义下,这个数为:1000000005

数据规模

对于 20% 数据,1n5000

对于 50% 数据,1n105

对于 100% 数据,1n1071m10

题解

首先根据欧拉反演 (具体可见数论学习笔记(一)(2024.7.25)),dnφ(d)=n,因此原式 =i=1nimdiσ0(d)μ(id)id

考虑改变枚举顺序,则原式 =i=1ndiimσ0(d)μ(id)id,考虑一个简单的 trick,枚举 1n 中所有数的因子,相当于枚举两个因子并保证它们的乘积在 1n 之间,那么原式就相当于 d=1nk=1nd(dk)mσ0(d)μ(k)k,此时就再次改变枚举顺序为 d=1ndmσ0(d)k=1ndμ(k)k

现在就可以通过线性筛筛出 1n 范围内的 σ0 函数 与 μ 函数 (具体可见数论学习笔记(二)(2024.8.16)),进一步预处理出 k=1ndμ(k)k,那么这道题就做完了。

完整代码

#include<bits/stdc++.h>
using namespace std;
const int PP = 1e7 + 9, MOD = 1e9 + 7;
int prime[PP], h[PP], sum[PP], isPrime[PP], p_cnt;
short mu[PP], g[PP];
int n, m, ans;
int qpow(int a, int b){
	int ret = 1;
	while(b > 0){
		if(b & 1)
			ret = 1ll * ret * a %  MOD;
		a = 1ll * a * a % MOD;
		b >>= 1;
	}
	return ret;
}
void getPrime(int n){
	mu[1] = h[1] = 1;
	for(int i = 2; i < n; i++){
		if(!isPrime[i]) {
			prime[++p_cnt] = i;
			g[i] = 1;
			h[i] = 2;
			mu[i] = -1;
		}
		for(int j = 1; j <= p_cnt && i * prime[j] < n; j++){
			int tmp = prime[j];
			isPrime[i * tmp] = tmp;
			if(i % tmp == 0) {
				g[i * tmp] = g[i] + 1;
				h[i * tmp] = h[i] / (g[i] + 1) * (g[i] + 2);
				mu[i * tmp] = 0;
				break;
			}
			g[i * tmp] = g[tmp];
			h[i * tmp] = h[i] * h[tmp];
			mu[i * tmp] = -mu[i];
		}
	}
	for(int i = 1; i <= n; i++)
		sum[i] = (sum[i - 1] + qpow(i, m + 1) * mu[i]) % MOD;
}
int main(){
	freopen("facsum.in", "r", stdin);
	freopen("facsum.out", "w", stdout);
	scanf("%d%d", &n, &m);
	getPrime(n + 1);
	for(int i = 1; i <= n; i++){
		int now = qpow(i, m);
		now = (1ll * now * h[i] % MOD * sum[n / i]) % MOD;
		ans = ((ans + now) % MOD + MOD) % MOD;
	}
	printf("%d\n", ans);
	return 0;
}

T2

题目描述

Mr.Hu 最近在研究等比数列,即形如:a,a2,a3,,an,

现在,Mr.Hu 想知道,对于给定的非负整数 a,上面这个无穷数列在摸 mod 意义下有多少项是本质不同
的。(保证 gcd(a,mod)=1)。

输入格式

1 行一个整数:T,表示数据组数。

接下来 T 行,每行两个整数:a,mod

输出格式

对于每组数据,输出一行,包含一个整数,表示模意义下本质不同的数有多少个。

输入样例

2
1 3
2 5

输出样例

1
4

样例解释

对于第一组数据,数列是:1,1,1,,1,

对于第二组数据,数列(取模以后)是:2,4,3,1,2,4,3,1,,总共有 4 个本质不同的数。

数据规模

对于 30% 数据,0a103,1mod103

对于 100% 数据,0a2×109,1mod2×109,且保证 gcd(a,mod)=1,1T100

题解

在这里介绍一下 BSGS 算法。

BSGS 是在 x,z,p 已知的情况下,用来求解 xyz(modp)y 的最小值的。

我们考虑将 y 除以 p,可以得到带余的式子 y=ap+b(b<p),那么这个式子也可以写成 y=(a+1)p)(pb)

现在用 c 代替 a+1d 代替 pb,那么 y=cpd,那么一开始的同余式就等价于 xcpz×xd(modp)

由于 x0xφ(p)1(modp),此处会形成一个循环节,那么 y 的最小值一定小于 φ(p),而 φ(p) 又一定小于 p,因此 cd 都在 p 级别。

那么就可以枚举同余式右边的 d,将算出来的值存入一个哈希表,再枚举同余式左边的 c,如果查到哈希表中有 xcp,那么就找到了答案,总时间复杂度为 O(p)

考虑本题如果出现 an1(modp),那么就找到了这个循环节,也就找到了本质不同的数的个数,因此本题解出上述的方程即可。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
int BSGS(int a, int b, int p){
	int k = sqrt(p) + 1;
	unordered_map <int, int> Hash;
	for(int i = 0, j = b % p; i < k; i++){
		Hash[j] = i;
		j = j * a % p;
	}
	int ak = 1;
	for(int i = 0; i < k; i++)
		ak = ak * a % p;
	for(int i = 1, j = ak; i <= k; i++){
		if(Hash.count(j))
			return i * k - Hash[j];
		j = j * ak % p;
	}
	exit(0);
}
int a, b, p, T;
signed main(){
	freopen("group.in", "r", stdin);
	freopen("group.out", "w", stdout);
	scanf("%lld", &T);
	while(T--){
		scanf("%lld%lld", &a, &p);
		printf("%lld\n", BSGS(a, 1, p));
	}
	return 0;
}

T3

题目描述

Mr.Hu 最近在学习组合数,他觉得这些数非常美丽。
于是,他写下了这样一个数:

(nl),(nl+1),(nl+2),,(nr1),(nr)

Mr.Hu 想知道,这些数里面,有多少个数是 5 的倍数。

输入格式

1 行一个整数:T,表示数据组数。

接下来 T 行,每行三个整数:l,r,n

输出格式

对于每组数据,输出一行,包含一个整数,表示答案。

输入样例

2
1 3 4
1 4 5

输出样例

0
4

样例解释

对于第一组数据,数列是:4,6,4,没有 5 的倍数,故答案为 0

对于第二组数据,数列是:5,10,10,5,有 4 个数是 5 的倍数,故答案为 4

数据规模

对于 20% 的数据,1n5000

对于 40% 的数据,1n109,1rl+15000

对于 100% 的数据,1n10180lrn,1T100

题解

首先根据 Lucas 定理,(nm)(npmp)(nmodpmmodp)(modp),那么一直推下去会推出 (nm)(n1m1)(n2m2)(nkmk)(modp)(ni,mi<p)

如果要让这个组合数等于 0 (等价于原式是 5 的倍数),那么变换后的式子中某一项就等于 0,就相当于至少存在一个 mi 大于 ni,如果把所有 ni 从左往右拼成一个数 N,把所有 mi 从左往右拼成一个数 M,那么就相当于 M 中有一位大于 N 中同一位,考虑到 MN 每个数位上的数都小于 5,可以对其做数位 DP。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 39;
int f[N][2] ,digl[N], digr[N], dign[N];
int DFS_l(int pos, int fl){
	if(pos == -1)
		return 1;
	if(f[pos][fl] != -1)
		return f[pos][fl];
	f[pos][fl] = 0;
	int ed = min((fl ? digl[pos] : 4), dign[pos]);
	for(int i = 0; i <= ed; i++)
		f[pos][fl] += DFS_l(pos - 1, fl && i == digl[pos]);
	return f[pos][fl];
}
int DFS_r(int pos, int fl){
	if(pos == - 1)
		return 1;
	if(f[pos][fl] != -1)
		return f[pos][fl];
	f[pos][fl] = 0;
	int ed = min((fl ? digr[pos] : 4), dign[pos]);
	for(int i = 0; i <= ed; i++)
		f[pos][fl] += DFS_r(pos - 1, fl && i == digr[pos]);
	return f[pos][fl];
}
signed main(){
	freopen("ccount.in", "r", stdin);
	freopen("ccount.out", "w", stdout);
	int t;
	scanf("%d", &t);
	while(t--){
		int l, r, n;
		scanf("%lld%lld%lld", &l, &r, &n);
		int L = l, R = r;
		l--;
		for(int i = 0; i < 30; i++){
			digl[i] = l % 5;
			digr[i] = r % 5;
			dign[i] = n % 5;
			l /= 5;
			r /= 5;
			n /= 5;
		}
		memset(f, -1, sizeof(f));
		int ansr = DFS_r(29, 1);
		memset(f, -1, sizeof(f));
		int ansl = DFS_l(29, 1);
		printf("%lld\n", (R - L + 1) - (ansr - ansl));
	}
	return 0;
}
posted @   JPGOJCZX  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示