题目
HDU
2≤n≤108
思路
考试时候一直在想什么杜教筛和分块,但是数组开不下而且好像错了
这个分数裂项简直绝了
考虑记
fn=1≤a<b≤ngcd(a,b)=1a+b≥n∑ab1
考虑递推,那么新增的必定有
b=n 而且还要减去
a+b=n−1 的方案
fn=fn−1+1≤a≤ngcd(a,n)=1∑an1−1≤a<b≤n−1gcd(a,b)=1a+b=n−1∑ab1
然后开始操作了…
发现减去的似乎有点搞头,记
gn=1≤a<b≤ngcd(a,b)=1a+b=n∑ab1
有边界
g2=0
然后因为
gcd(a,b)=gcd(a,a+b)=gcd(a,n)=gcd(b,n),ab1=n1(a1+b1)
于是有
gn=n11≤a<b≤ngcd(a,b)=1a+b=n∑a1+b1
gn=n11≤a≤ngcd(a,n)=1∑a1
惊奇的发现和
fn 的表达式扯上关系
于是
fn=fn−1+gn−gn−1
这真的很离谱,
然后
fn−1=fn−2+gn−1−gn−2
代入,一直到
fn=f2−g2+gn=21+gn
然后只用求
gn
接着莫比乌斯反演
gn=n1i=1∑ni1[gcd(i,n)=1]=n1i=1∑ni1d∣(i,n)∑μd=n1d∣n∑μdd1i=1∑⌊dn⌋i1=n1d∣n∑μ(d)d1S(⌊dn⌋)
然后就可以
O(n) 算出
S(n)
然后由于空间限制
512Mb ,一个
1e8 的数组是
350Mb 左右,你不能
O(n) 筛出
μ ,要将
n 质因数分解后类似二进制枚举搞出
gn
代码
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<deque>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<vector>
#include<climits>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
LL read(){
LL f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return f*x;
}
#define INF 0x3f3f3f3f
#define Mod 998244353
#define MAXN 100000000
inline int Sub(register int x,register int y){x-=y;return x<0?x+Mod:x;}
inline int Add(register int x,register int y){x+=y;return x>=Mod?x-Mod:x;}
inline int Mul(register LL x,register int y){x*=y;return x>=Mod?x%Mod:x;}
int Pow(int x,LL y){
int ret=1;
while(y){
if(y&1) ret=Mul(ret,x);
x=Mul(x,x);
y>>=1;
}
return ret;
}
int n,inv[MAXN+5],cnt,p[30],ans;
void DFS(int x,int d,int u){
if(x>cnt){
ans=Add(ans,Mul(Mul(u,Sub(inv[d],inv[d-1])),inv[n/d]));
return ;
}
DFS(x+1,d,u);
DFS(x+1,d*p[x],Mod-u);
return ;
}
int main(){
inv[1]=1;
for(int i=2;i<=MAXN;i++)
inv[i]=(Mod-(1ll*Mod/i*inv[Mod%i]%Mod))%Mod;
for(int i=2;i<=MAXN;i++)
inv[i]=Add(inv[i],inv[i-1]);
int T=read();
while(T--){
ans=0,cnt=0,n=read();
int tmp=n;
for(int i=2;i*i<=tmp;i++)
if(tmp%i==0){
p[++cnt]=i;
while(tmp%i==0)
tmp/=i;
}
if(tmp>1)
p[++cnt]=tmp;
if(n!=2)
DFS(1,1,1);
else ans=0;
ans=Mul(ans,Sub(inv[n],inv[n-1]));
printf("%d\n",Add(ans,inv[2]-1));
}
return 0;
}