简单题意
算法
先分块,有
令函数
对,通过差分有
,显然f(i,i)通过线性欧拉筛可以
预处理.
所以显然只需要考虑上界为n时的情况,的跑一边f(i,n)即可。
这题卡常很严,所以离线查询(__int128长见识了),整体复杂度为
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e7 + 7;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
ll gcd(ll a,ll b){return b ? gcd(b,a % b) : a;}
int lcm(int a,int b){return a / gcd(a,b) * b;}
ll fpow(ll a,ll b)
{
ll res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void read(__int128 &x) {
static char ch;static bool neg;
for(ch=neg=0;ch<'0' || '9'<ch;neg|=ch=='-',ch=getchar());
for(x=0;'0'<=ch && ch<='9';(x*=10)+=ch-'0',ch=getchar());
x=neg?-x:x;
}
int phi[N],prime[N],cnt;
bool isprime[N];
ll f[N];
void get_phi()
{
phi[1] = 1;
for(int i = 2;i < N;++i){
if(!isprime[i]){
prime[++cnt] = i;
phi[i] = i - 1;
}
for(int j = 1;j <= cnt && i * prime[j] < N;++j){
isprime[i * prime[j]] = 1;
if(i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for(int i = 1;i * i < N;++i){
int p = i * i;
for(int j = i * i;j < N;j += i){
f[j] = (f[j] + i * phi[j / i]) % mod;
if(p < j) f[j] = (f[j] + (j / i) * phi[i]) % mod;
}
}
}
struct node{
__int128 n;
int id;
}a[20];
bool cmp(node a,node b)
{
return a.n < b.n;
}
//ll n;
ll ans[20],pos[20];
int main()
{
//freopen("in.txt","r",stdin);
get_phi();
int t;
scanf("%d",&t);
for(int i = 0;i < t;++i){
read(a[i].n);
a[i].id = i;
//scanf("%lld",&n);
}
sort(a,a + t,cmp);
for(__int128 i = 1,cnt = 0;i * i * i < a[t - 1].n;++i){
if((i + 1) * (i + 1) * (i + 1) > a[cnt].n){
if(cnt == t - 1){
pos[cnt] = i;
break;
}
while((i + 1) * (i + 1) * (i + 1) > a[cnt].n){
pos[cnt] = i;
cnt++;
ans[cnt] = ans[cnt - 1];
}
}
ans[cnt] = (ans[cnt] + 3LL * (i + 1) * f[i] + i) % mod;
if((i + 1) * (i + 1) * (i + 1) == a[cnt].n) ans[cnt] = (ans[cnt] + i + 1) % mod,pos[cnt] = 0;
}
for(int jq = 0;jq < t;++jq){
if(pos[jq]){
ll rnt = a[jq].n % pos[jq],ret = a[jq].n / pos[jq] % mod;
for(ll i = 1;i * i <= pos[jq];++i){
ll l = pos[jq] / i;
if(pos[jq] % i == 0){
ans[jq] = (ans[jq] + (rnt / i) * phi[i]) % mod;
if(i * i < pos[jq]) ans[jq] = (ans[jq] + (rnt / l) * phi[l]) % mod;
}
i = pos[jq] / l;
}
ans[jq] = (ans[jq] + (ret - (pos[jq] * pos[jq])) % mod * f[pos[jq]] % mod + pos[jq] + mod) % mod;
}
}
for(int i = 0;i < t;++i){
for(int j = 0;j < t;++j)
if(a[j].id == i)printf("%lld\n",ans[j]);
}
return 0;
}