P6810 「MCOI-02」Convex Hull 凸包 题解

题目链接

看绝大多数题解都是莫反,这里写个不用莫反的(其实就是推式子)

∑ i = 1 n ∑ j = 1 m τ ( i ) τ ( j ) τ ( gcd ⁡ ( i , j ) ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\tau(i)\tau(j)\tau(\gcd(i,j)) i=1nj=1mτ(i)τ(j)τ(gcd(i,j))
∑ i = 1 n τ ( i ) ∑ j = 1 m τ ( j ) τ ( gcd ⁡ ( i , j ) ) \sum\limits_{i=1}^{n}\tau(i)\sum\limits_{j=1}^{m}\tau(j)\tau(\gcd(i,j)) i=1nτ(i)j=1mτ(j)τ(gcd(i,j))
∑ i = 1 n τ ( i ) ∑ j = 1 m τ ( j ) ∑ k ∣ i , k ∣ j 1 \sum\limits_{i=1}^{n}\tau(i)\sum\limits_{j=1}^{m}\tau(j)\sum\limits_{k|i,k|j}1 i=1nτ(i)j=1mτ(j)ki,kj1

接下来优先枚举 k k k
∑ k = 1 min ⁡ ( n , m ) ∑ k ∣ i , i ≤ n τ ( i ) ∑ k ∣ j , j ≤ m τ ( j ) \sum\limits_{k=1}^{\min(n,m)}\sum\limits_{k|i,i\le n}\tau(i)\sum\limits_{k|j,j \le m}\tau(j) k=1min(n,m)ki,inτ(i)kj,jmτ(j)
s k = ∑ k ∣ i , i ≤ n τ ( i ) s_k=\sum\limits_{k|i,i\le n}\tau(i) sk=ki,inτ(i) c k = ∑ k ∣ i , i ≤ m τ ( i ) c_k=\sum\limits_{k|i,i\le m}\tau(i) ck=ki,imτ(i)
那么原式等于 ∑ k = 1 min ⁡ ( n , m ) s k ⋅ c k \sum\limits_{k=1}^{\min(n,m)}s_k \cdot c_k k=1min(n,m)skck

我们可以 O ( n log ⁡ n ) O(n \log n) O(nlogn) 预处理出 τ ( i ) , s i , c i \tau(i),s_i,c_i τ(i),si,ci,代入上式即可

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int Maxn=2000000+10;
int f[Maxn];
long long s[Maxn],c[Maxn];
int n,m;
long long p,ans;
inline void check(long long &x,long long y)
{
    
    
	x=(x+y)%p;
}
inline int read()
{
    
    
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
    
    if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return s*w;
}
int main()
{
    
    
	n=read(),m=read(),p=read();
	if(n>m)swap(n,m);
	for(int i=1;i<=m;++i) 
	for(int j=i;j<=m;j+=i)
	++f[j];
	for(int i=1;i<=n;++i)
	{
    
    
		for(int j=i;j<=n;j+=i)
		check(s[i],f[j]);
		for(int j=i;j<=m;j+=i)
		check(c[i],f[j]);
		check(ans,(c[i]*s[i])%p);
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Brian_Pan_/article/details/108560167