Math is Simple[杭电2020第一场][数学变形][数论变换]

文章目录

  • 题目
  • 思路
  • 代码

题目

HDU
在这里插入图片描述

2 ≤ n ≤ 1 0 8 2\le n\le 10^8 2n108

思路

考试时候一直在想什么杜教筛和分块,但是数组开不下而且好像错了
这个分数裂项简直绝了
考虑记
f n = ∑ 1 ≤ a < b ≤ n g c d ( a , b ) = 1 a + b ≥ n 1 a b f_n=\sum_{\begin{matrix}1\le afn=1a<bngcd(a,b)=1a+bnab1
考虑递推,那么新增的必定有 b = n b=n b=n 而且还要减去 a + b = n − 1 a+b=n-1 a+b=n1 的方案
f n = f n − 1 + ∑ 1 ≤ a ≤ n g c d ( a , n ) = 1 1 a n − ∑ 1 ≤ a < b ≤ n − 1 g c d ( a , b ) = 1 a + b = n − 1 1 a b f_n=f_{n-1}+\sum_{\begin{matrix}1\le a\le n\\gcd(a,n)=1\end{matrix}}\frac{1}{an}-\sum_{\begin{matrix}1\le afn=fn1+1angcd(a,n)=1an11a<bn1gcd(a,b)=1a+b=n1ab1
然后开始操作了…
发现减去的似乎有点搞头,记 g n = ∑ 1 ≤ a < b ≤ n g c d ( a , b ) = 1 a + b = n 1 a b g_n=\sum_{\begin{matrix}1\le agn=1a<bngcd(a,b)=1a+b=nab1
有边界 g 2 = 0 g_2=0 g2=0
然后因为 g c d ( a , b ) = g c d ( a , a + b ) = g c d ( a , n ) = g c d ( b , n ) , 1 a b = 1 n ( 1 a + 1 b ) gcd(a,b)=gcd(a,a+b)=gcd(a,n)=gcd(b,n),\frac{1}{ab}=\frac{1}{n}(\frac{1}{a}+\frac{1}{b}) gcd(a,b)=gcd(a,a+b)=gcd(a,n)=gcd(b,n),ab1=n1(a1+b1)
于是有
g n = 1 n ∑ 1 ≤ a < b ≤ n g c d ( a , b ) = 1 a + b = n 1 a + 1 b g_n=\frac{1}{n}\sum_{\begin{matrix}1\le agn=n11a<bngcd(a,b)=1a+b=na1+b1
g n = 1 n ∑ 1 ≤ a ≤ n g c d ( a , n ) = 1 1 a g_n=\frac{1}{n}\sum_{\begin{matrix}1\le a\le n\\gcd(a,n)=1\end{matrix}}\frac{1}{a} gn=n11angcd(a,n)=1a1
惊奇的发现和 f n f_n fn 的表达式扯上关系
于是
f n = f n − 1 + g n − g n − 1 f_n=f_{n-1}+g_n-g_{n-1} fn=fn1+gngn1
这真的很离谱,
然后 f n − 1 = f n − 2 + g n − 1 − g n − 2 f_{n-1}=f_{n-2}+g_{n-1}-g_{n-2} fn1=fn2+gn1gn2
代入,一直到
f n = f 2 − g 2 + g n = 1 2 + g n f_n=f_2-g_2+g_n=\frac{1}{2}+g_n fn=f2g2+gn=21+gn
然后只用求 g n g_n gn
接着莫比乌斯反演
g n = 1 n ∑ i = 1 n 1 i [ g c d ( i , n ) = 1 ] = 1 n ∑ i = 1 n 1 i ∑ d ∣ ( i , n ) μ d = 1 n ∑ d ∣ n μ d 1 d ∑ i = 1 ⌊ n d ⌋ 1 i = 1 n ∑ d ∣ n μ ( d ) 1 d S ( ⌊ n d ⌋ ) g_n=\frac{1}{n}\sum_{i=1}^n\frac{1}{i}[gcd(i,n)=1]=\frac{1}{n}\sum_{i=1}^n\frac{1}{i}\sum_{d|(i,n)}\mu_d\\=\frac{1}{n}\sum_{d|n}\mu_d\frac{1}{d}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\frac{1}{i}=\frac{1}{n}\sum_{d|n}\mu(d)\frac{1}{d}S(\lfloor\frac{n}{d}\rfloor) gn=n1i=1ni1[gcd(i,n)=1]=n1i=1ni1d(i,n)μd=n1dnμdd1i=1dni1=n1dnμ(d)d1S(dn)
然后就可以 O ( n ) O(n) O(n) 算出 S ( n ) S(n) S(n)
然后由于空间限制 512 M b 512Mb 512Mb ,一个 1 e 8 1e8 1e8 的数组是 350 M b 350Mb 350Mb 左右,你不能 O ( n ) O(n) O(n) 筛出 μ \mu μ ,要将 n n n 质因数分解后类似二进制枚举搞出 g n g_n gn

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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;
}

你可能感兴趣的:(数论变换)