2 条题解
-
2
前置知识:莫比乌斯反演。
首先,考虑对于一组 ,令 。
直接用莫比乌斯反演一下。
$$S=\sum_{i=1}^n \sum_{j=i}^n \sum_{d|g} \sum_{d'|g'} \mu(d) \mu(d') $$令 表示 是否满足 ,可以是 ,不可以是 。
然后发现,对于一组 ,满足条件的 实际上就是我们在上面那个式子枚举的 。
$$S=\sum_{i=1}^n \sum_{j=i}^n \sum_{d|g} \sum_{d'|g'} \mu(d) \mu(d')\\ = \sum_{i=1}^n \sum_{j=i}^n \sum_{a=1}^n \sum_{b=1}^n \mu(a)\mu(b)f(a,b,i,j) $$这是一个比较复杂的式子,我们考虑化简。
设 表示对于一组 ,有多少个 满足 是 的倍数, 是 的倍数。
可以得到
$$\sum_{i=1}^n \sum_{j=i}^n f(a,b,i,j)=\frac{s(a,b)(s(a,b)+1)}{2} $$然后去化简原式,得到
$$\sum_{a=1}^n \sum_{b=1}^n \mu(a)\mu(b) \frac{s(a,b)(s(a,b)+1)}{2} $$然后就可以发现,只有满足 是 的倍数的位置才会对答案产生贡献,这样的位置只有 个,此时 要满足是这些位置的 的因数。
由于 ,对于一个位置,它的因数最多只有 个,先预处理这些位置,直接枚举就好了。
时间复杂度 。
代码
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; int n,p[N],mu[N],b[N],P[N],cnt,s[N],vis[N]; vector<int> cana,vec[N],canb; long long ans; void work(int maxn){//预处理莫比乌斯函数 mu[1]=0; for(int i=2;i<=maxn;i++){ if(!b[i])P[++cnt]=i,mu[i]=1; for(int j=1;j<=cnt&&P[j]*i<=maxn;j++){ b[P[j]*i]=1; if(i%P[j]==0){ mu[i*P[j]]=0; break; } mu[i*P[j]]=-mu[i]; } if(mu[i]){//如果值为零,对答案显然没有贡献,所以只考虑不为零的 cana.push_back(i); for(int j=i;j<=maxn;j+=i)vec[j].push_back(i); } } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&p[i]); work(n); for(int a:cana){ canb.clear(); for(int i=a;i<=n;i+=a){ for(int b:vec[p[i]]){ s[b]++; if(!vis[b])vis[b]=1,canb.push_back(b); } } for(int b:canb){ ans=ans+1ll*mu[a]*mu[b]*s[b]*(s[b]+1)/2; s[b]=0; vis[b]=0; } } printf("%lld",ans); }
-
1
题意
给定一个长度为 的排列 ,求有多少 满足 。
分析
看到 计数题,我们考虑莫比乌斯反演。 然后就开始推:
$$\begin{aligned} \sum_{1\le i\le n}\sum_{i\le j\le n}[\gcd(i,j)>1][\gcd(p_i,p_j)>1]&=\sum_{1\le i\le n}\sum_{i\le j\le n}\sum_{a|i,a|j}\mu(a)\sum_{b|p_i,b|p_j}\mu(b)\\&=\sum_{1\le a\le n}\sum_{1\le b\le n}\mu(a)\mu(b)\sum_{1\le i\le j\le n}[a|i][a|j][b|p_i][b|p_j]\\&=\sum_{1\le a\le n}\sum_{1\le b\le n}\mu(a)\mu(b)\dfrac{f(a,b)\times(f(a,b)+1)}{2} \end{aligned} $$其中 。
然后,由于在本题范围内一个数的 值不为 的约数有最多有 个,直接枚举 ,然后枚举 和 并统计每个 的 ,最后枚举 统计答案。
#include<bits/stdc++.h> using namespace std; #define ll long long int n; int per[200005]; vector<int> d[200005],vec,v; int mu[200005]; int check[200005]; int num[200005]; int prime[200005],tot; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&per[i]); for(int i=2;i<=n;i++){ if(!check[i]){ mu[i]=-1; prime[++tot]=i; } for(int j=1;j<=tot&&prime[j]<=n/i;j++){ check[i*prime[j]]=1; if(i%prime[j]==0){ mu[i*prime[j]]=0; break; }else mu[i*prime[j]]=-mu[i]; } if(mu[i]){ vec.push_back(i); for(int j=i;j<=n;j+=i)d[j].push_back(i); } } ll ans=0; for(int a:vec){ v.clear(); for(int i=a;i<=n;i+=a) for(int b:d[per[i]]){ if(!num[b])v.push_back(b); num[b]++; } for(int b:v){ ans+=1ll*mu[a]*mu[b]*num[b]*(num[b]+1)/2; // printf("%d %d %lld\n",a,b,ans); num[b]=0; } } printf("%lld\n",ans); return 0; }
- 1
信息
- ID
- 56
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 2
- 上传者