题目描述
新冠疫情爆发以来,病毒不断地扩散传播,而人类也在不断采取各种措施遏制病毒传播。于是我们可以为这场抗疫斗争建立一个数学模型,将病毒的不断传播和人类的不断采取措施抽象为一场双方轮流行动的博弈。我们认为人类与病毒的每轮行动都可以选择一个正整数作为行动值来评估。然而,出于各方面限制,双方的所有行动值总和
必须等于一个数m,且每次的行动值不能超过对方上轮的行动值。对人类来说,要遏制疫情,就应成为最后行动的一方,也就是说,在本方的某次行动后,行动值总和m恰好被消耗完。
假设人类先行动,那么我们只需一鼓作气消耗完所有m点行动值,就能战胜病毒。然而在最开始的阶段出于认识不到疫情的严重性,往往最难开展大规模行动。出于这个原因,我们令hm表示在行动值总和为m的情况下,人类(即先行动方)的第一次行动最少要多少行动值,才能保证自己必胜。
出于统计需要,某科学家记f[i]=∑m|i hm,并想知道 。方便起见,对998244353取模。你能帮个忙吗?
输入格式
第一行输入一个数 。
输出格式
一行一个数,表示答案。
样例输入
3
样例输出
6
限制及约定
本题采用子任务形式评测。
子任务编号 | n<= | 分值 |
---|---|---|
1 | 3 | 1 |
2 | 1000 | 9 |
3 | 10^5 | 31 |
4 | 10^11 | 28 |
5 | 5*10^13 | 26 |
6 | 10^15 | 5 |
对于所有数据,满足1<=n<=10^15。
思路
首先考虑如何计算hm
如果m为奇数,那么显然hm=1(你一个我一个,先手胜)
如果m为偶数,那么我们可以选一个数k,使得(m/k)%2==1,显然k最小为lowbit(m)
所以hm=lowbit(m)
下面我们来考虑计算f(n)的前缀和,则
们考虑枚举hi的取值,并统一计算其贡献。方便起见,我们记
复杂度O(sqrt(n))
代码
#include<bits/stdc++.h>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int mod=998244353,N=1e6+77;
void inc(int &x,int y)
{
x=x+y>=mod?x+y-mod:x+y;
}
long long n;
int ans,val[N];
int work(long long x)
{
long long ans=0;
int sq=sqrt(x);
for(int i=1;i<=sq;i++)ans+=(x/i);
ans=(2*ans-1ll*sq*sq)%mod;
return ans;
}
int main()
{
scanf("%lld",&n);
for(long long a=1;a<=n;a<<=1)
inc(ans,1ll*(a-(a>>1))%mod*work(n/a)%mod);
printf("%d",ans);
return 0;
}