CF1542C Strange Function

这篇博客介绍了CF1542C问题的解决方案,探讨了定义一个特殊函数f(i),该函数表示不为i的因子的最小正整数。博主首先分析奇数和偶数的情况,发现偶数的f(i)每隔特定周期会变化。通过建立因子表,确定了周期与f(i)的关系,提出利用最小公倍数计算每个f(i)的周期,并在遍历过程中按周期累加求和,最后给出了代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Before all

唉又没有时间打 CF,只好事后自己做了。。。

题目大意

定义一个函数 f ( i ) f(i) f(i) 表示不为 i i i 的因子的最小正整数,比如 f ( 1 ) = 2 , f ( 2 ) = 3 , f ( 4 ) = 3 f(1)=2,f(2)=3,f(4)=3 f(1)=2,f(2)=3,f(4)=3。现给出一个 n ( n ≤ 1 0 16 ) n(n\le 10^{16}) n(n1016),求 ∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) i=1nf(i) 的值 mod ⁡ 1 0 9 + 7 \operatorname{mod} 10^9+7 mod109+7

Solution

从简单开始思考,显然,所有的奇数的 f ( i ) f(i) f(i) 都是 2 2 2。所以我们来考虑偶数。

偶数必然有因子 1 , 2 1,2 1,2,所以我们暂且认为偶数的 f ( i ) = 3 f(i)=3 f(i)=3。为了接下来分析方便起见,我将偶数及其函数值打成一张表:

i i i 2 2 2 4 4 4 6 6 6 8 8 8 10 10 10 12 12 12 14 14 14 16 16 16 18 18 18 … \dots
f ( i ) f(i) f(i) 3 3 3 3 3 3 4 4 4 3 3 3 3 3 3 5 5 5 3 3 3 3 3 3 4 4 4 … \dots

不难看出,每 6 6 6 个会出现一个 4 4 4,每 12 12 12 个会出现一个 5 5 5……

那么这个 6 6 6 12 12 12 是哪里来的呢?

我们不妨把 f ( i ) = 3 f(i)=3 f(i)=3 的偶数表示为 2 2 2,除此以外的因子都比 3 3 3 大的形式。那么 6 6 6 就是 2 × 3 2\times 3 2×3,除此以外因子都比 4 4 4 大……

所以,我们可以先打表来算这个每一个 f ( i ) f(i) f(i) 的出现周期。我们需要保证这个值是包含因子 1 , 2 , … , [ f ( i ) − 1 ] 1, 2, \dots, [f(i)-1] 1,2,,[f(i)1] 的最小值,设 f ( i ) − 1 f(i)-1 f(i)1 的周期为 s s s,那么这个值只需要在 s s s 的基础上使得它能够被 f ( i ) − 1 f(i)-1 f(i)1 整除,所以就是 f ( i ) − 1 f(i)-1 f(i)1 s s s 的最小公倍数。

最后统计答案的时候,遍历每个 f ( i ) f(i) f(i) 的周期,由于我们是逐一考虑 f ( i ) f(i) f(i) 的,所以每次只要加上 ⌊ n s ⌋ \left\lfloor\dfrac{n}{s}\right\rfloor sn 即可。

Code

#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
using namespace std;
const ll MAXN=1e16;
const ll MOD=1e9+7;
ll top[110];
void solve(){
	ll n;
	scanf("%lld",&n);
	ll ans=n*2%MOD;//加上奇数的值,并先把偶数的 3 加上 2
	ans=(ans+n/2)%MOD;//先钦定所有偶数都是 3,由于上一行中已经加了 2,所以这里每个偶数只要 +1
	for(int i=4;top[i]<=n;i++){
		ans=(ans+n/top[i])%MOD;
		//同理,我已经加了小 1 的值,所以这里每次只需要增加 1 就行
	}
	printf("%lld\n",ans);
}
ll gcd(ll x,ll y){return x%y==0?y:gcd(y,x%y);}
int main()
{
	for(ll i=4,cur=2;cur<=MAXN;i++){
		ll g=gcd(i-1,cur);
		cur=cur*(i-1)/g;
		top[i]=cur;
	}//打表,top[i] 表示 f(x)=i 的周期
	int T;
	for(scanf("%d",&T);T--;)
		solve();
	return 0;
}
/*

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值