hdu 6053 TrickGCD 筛法+莫比乌斯函数+分块处理
来源:互联网 发布:施耐德可编程编程软件 编辑:程序博客网 时间:2024/06/16 09:53
题目链接
题意:
给你n个数字,每个位置的数字可以小于等于a[i],求所有gcd(l,r)都满足大于等于2的情况数;
思路:
首先,比较好想到的就是枚举gcd,那么每个ai,都有ai/gcd 的选择,然后n个数累乘.但是我们发现,比如 6 6 的时候 2 3 都计算了6 ,6也算了6.有很多重复的情况没法处理,所以想到了容斥,可是当时真的不知道怎么去容斥,感觉太多了很复杂.
首先分块处理, 当我们枚举gcd为d的时候, 那么从(kd,(k+1)d-1) 对答案的贡献都是为k,那么我们就可以把这些块一个个的分开处理, 开一个sum,记录a数组中,数的范围属于(k*d,(k+1)d-1)的数有多少个,最后快速幂一下就可以快速计算出当gcd为d的时候的贡献,以此类推.
那么我们下面来看怎么去重
1.筛法.
去重的时候我们从后往前考虑,因为每一个数都会多算了一次他的倍数所以我们要将他减去,如果我们从前往后考虑,那么有些答案并不是最终的结果,所以我们从后往前.因为最大的gcd 后面没有倍数,不会重复,这样依次往下减,只保留自己的就好了。
#include<bits/stdc++.h>#define Ri(a) scanf("%d", &a)#define Rl(a) scanf("%lld", &a)#define Rf(a) scanf("%lf", &a)#define Rs(a) scanf("%s", a)#define Pi(a) printf("%d\n", (a))#define Pf(a) printf("%lf\n", (a))#define Pl(a) printf("%lld\n", (a))#define Ps(a) printf("%s\n", (a))#define W(a) while(a--)#define CLR(a, b) memset(a, (b), sizeof(a))#define MOD 1000000007#define inf 0x3f3f3f3f#define exp 0.00000001#define pii pair<int, int>#define mp make_pair#define pb push_backusing namespace std;typedef long long ll;const int maxn=1e5+10;const int N=1e5+5;int a[maxn];ll dp[maxn];ll sum[maxn];int t,n; ll qmod(ll a,ll b){ ll res=1; while(b) { if(b&1) res=res*a%MOD; b>>=1; a=a*a%MOD; } return res;}int main(){ scanf("%d",&t); int ca=1; while(t--) { int mi=inf; memset(dp,0,sizeof(dp)); memset(sum,0,sizeof(sum)); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); mi=min(mi,a[i]); sum[a[i]]++; } ll a,b; for(int i=1;i<=N;i++) sum[i]+=sum[i-1]; for(int i=2;i<=mi;i++) { dp[i]=1; for(int j=i;j<=N;j+=i) { if(j+i-1>N) b=sum[N]-sum[j-1]; else b=sum[i+j-1]-sum[j-1]; if(b==0) continue; a=j/i; dp[i]=(dp[i]*qmod(a,b))%MOD; } } ll ans=0; for(int i=N;i>=2;i--) { for(int j=2*i;j<=N;j+=i) dp[i]=(dp[i]-dp[j]+MOD)%MOD; ans = (ans + dp[i]) % MOD; } printf("Case #%d: %lld\n",ca++,ans); } return 0;}
2.巧妙利用莫比乌斯函数
其实我们知道,莫比乌斯就是容斥. 公式如下
我们只考虑质因子,设当前gcd=d,计算贡献时 d可以拆分为k个质数的乘积,由于这里是对贡献进行累加操作,所以我们可以知道,当k为偶数我们需要减,当k为奇数我们需要加,而根据莫比乌斯函数可以看出,当k为偶数为+,奇数为-,正好是一个相反的,所以这里利用相反的莫比乌斯函数,就可以直接去重了,
#include<bits/stdc++.h>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e5+10;const int N =1e5;int prime[maxn];int mu[maxn];int vis[maxn];ll sum[maxn];int t,n;//求莫比乌斯函数// mu[i] == 1 表示质因子不重复且个数为偶// mu[i] ==-1 表示质因子不重复且个数为奇// mu[i] == 0 表示存在重复的质因子void mobius(){int cnt=0;memset(vis,0,sizeof(vis));mu[1]=1;//n=1为1 for(int i=2;i<=N;i++){if(!vis[i])prime[++cnt]=i,mu[i]=-1;for(int j=1;prime[j]*i<=N;j++){vis[i*prime[j]]=1;if(i%prime[j]==0){mu[i*prime[j]]=0;break;}mu[i*prime[j]]=-mu[i];}}return ;}ll qmod(ll a,ll b){ll res=1;while(b){if(b&1)res=res*a%mod;b>>=1;a=a*a%mod;}return res;}int main(){scanf("%d",&t);int ca=1;memset(mu,0,sizeof(mu));memset(prime,0,sizeof(prime));mobius(); while(t--){memset(sum,0,sizeof(sum)); scanf("%d",&n);int x;int mi=maxn;for(int i=0;i<n;i++){scanf("%d",&x);sum[x]++;mi=min(mi,x);}for(int i=1;i<=N;i++)sum[i]+=sum[i-1];ll ans=0;ll res=0;for(int i=2;i<=mi;i++){if(mu[i]==0)//存在重复的质因子直接跳过 continue;ll a,b;res=1;for(int j=i;j<=N;j+=i){if(j+i-1>N)b=sum[N]-sum[j-1];elseb=sum[i+j-1]-sum[j-1];a=j/i;if(b==0)continue;res=(res*qmod(a,b))%mod;}if(mu[i]==-1)ans=(ans+res)%mod;elseans=(ans-res+mod)%mod;}printf("Case #%d: %lld\n",ca++,ans);}return 0;}
好的学习资料
阅读全文
0 0
- hdu 6053 TrickGCD 筛法+莫比乌斯函数+分块处理
- HDU 6053 TrickGCD(莫比乌斯反演+分块)
- TrickGCD----筛法/分块/莫比乌斯函数
- HDU 6053 TrickGCD (莫比乌斯函数+分块筛)
- hdu 6053 TrickGCD [莫比乌斯函数]
- Hdu-6053 TrickGCD(莫比乌斯函数)
- HDU 6053 TrickGCD (莫比乌斯函数)
- HDU 6053 TrickGCD(莫比乌斯函数)
- HDU 6053 TrickGCD 莫比乌斯反演||筛法
- hdu 6053 TrickGCD 【容斥&筛法|莫比乌斯】
- hdu 6053 TrickGCD 容斥 莫比乌斯
- 【HDU 6053 TrickGCD】 + 莫比乌斯反演
- HDU 6053 TrickGCD(莫比乌斯反演)
- 【数论-莫比乌斯】hdu 6053 TrickGCD
- hdu 6053 TrickGCD(莫比乌斯反演)
- HDU 6053 TrickGCD(莫比乌斯反演+前缀和)
- HDU 6053 TrickGCD(莫比乌斯反演)
- hdu 6053 TrickGCD(容斥,分段,莫比乌斯函数)
- HDU 6053 容斥dp 或 莫比乌斯反演
- Python修改数据中的字符串数据列
- 莫比乌斯函数
- oracle
- 针对百家号抓取项目
- hdu 6053 TrickGCD 筛法+莫比乌斯函数+分块处理
- 数据库优化
- 剑指offer——链表中倒数第k个节点
- 日常学习2017.7.28
- 多态&多态对象模型
- python学习(三)----集合类型内建方法总结
- c# 后台给控件加样式
- 安装SQL Server2008后 ,wamp无法启动apache
- hdu 6055 Regular polygon