https://nanti.jisuanke.com/t/41300
题意:对1e5范围内的n求以上这么个东西%998244353
我太难了。这个题太难了。
前半部分是题解的内容,我作为一个数论菜鸡琢磨了一琢磨也看懂了,就是不会NTT的我后面看不懂,问过大佬之后写了点解释咳咳。
fi表示的是欧拉函数值==i的数的个数
然后,对于一个i,绿色的部分是好求的,然后就是求红色圈出来的部分
我们假设有一个多项式A,它的系数
还有另一个多项式B,它的系数
经思索(所以到底是怎么思索出来的啊喂),多项式A*B的第i次项系数
然而j=0的时候aj=0,所以j直接从1开始求和也是可以的,这样的话就和红圈部分长得一毛一样了
所以最终结果=
这个c用NTT算,其他的直接算。
另外,经观察,根号2的指数都是偶数,所以最后实际上用到的可以理解为根号2的平方(就是在指数中提出一个2,然后根号2平方一下)。根号2不好算,所以我们暴力找到一个数x,使得x^2%mod==2,然后用这个数代替根号2去计算就好啦
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+5;
const ll mo=998244353;
ll fpow(ll a, ll b){
ll ans=1;
while(b>0){if(b&1)ans=ans*a%mo;b>>=1;a=a*a%mo;}
return ans;
}
ll D(ll x) {
((x>=mo) && (x-=mo)) || ((x<0) && (x+=mo));
return x;
}
void NTT(ll a[],ll n,ll op) {
for(ll i=1,j=n>>1;i<n-1;++i) {
if(i<j) swap(a[i],a[j]);
ll k=n>>1;
while(k<=j) {
j-=k;
k>>=1;
}
j+=k;
}
for(ll len=2;len<=n;len<<=1) {
ll rt=fpow(3,(mo-1)/len);
for(ll i=0;i<n;i+=len) {
ll w=1;
for(ll j=i;j<i+len/2;++j) {
ll u=a[j],t=1LL*a[j+len/2]*w%mo;
a[j]=D(u+t),a[j+len/2]=D(u-t);
w=1LL*w*rt%mo;
}
}
}
if(op==-1) {
reverse(a+1,a+n);
ll in=fpow(n,mo-2);
for(ll i=0;i<n;++i)
a[i]=1LL*a[i]*in%mo;
}
}
void conv(ll* a,ll h1,ll* b,ll h2,ll* c) {//h是最高次项次数
ll s=1;
while(s<h1+h2+1)s<<=1;
NTT(a,s,1);NTT(b,s,1);
for(ll i=0;i<s;++i)
c[i]=1LL*a[i]*b[i]%mo;
NTT(c,s,-1);
// NTT(a,n,-1);
}
ll qp(ll a,ll b,ll mod){
a%=mod;
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
ll a[maxn],b[maxn],c[maxn],d[maxn],p[maxn],f[maxn];
ll primes[maxn],phi[maxn],fl[maxn],cnt;
int main(){
int t,n;
scanf("%d",&t);
memset(fl,1,sizeof(fl));
fl[1]=0;
phi[1]=1;
for (int i=2;i<=1e5;i++){
if (fl[i]) primes[++cnt]=i,phi[i]=i-1;
for (int j=1;j<=cnt && i*primes[j]<=1e5;j++){
fl[i*primes[j]]=0;
if (i%primes[j]==0) {phi[i*primes[j]]=phi[i]*primes[j]; break;}
else phi[i*primes[j]]=phi[i]*phi[primes[j]];
}
}
while(t--){
scanf("%d",&n);
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for(ll i=1;i<=n;i++) f[phi[i]]++;
for(ll i=0;i<=n;i++){
d[i]=a[i]=i*f[i]%mo*qp(116195171ll,i*i%(mo-1),mo)%mo,b[i]=qp(116195171ll,-i*i%(mo-1)+mo-1,mo);
}
conv(a,n,b,n,c);//此时c中位各次系数,从低到高
ll ans=0;
for(ll i=1;i<=n;i++){
ans=(ans+2*d[i]%mo*c[i]%mo-d[i]*d[i]%mo)%mo;
}
ans=(ans+mo)%mo;
printf("%lld\n",ans);
}
return 0;
}