HDU-6053 TrickGCD 前缀和数组,莫比乌斯函数
来源:互联网 发布:尘埃落定 知乎 编辑:程序博客网 时间:2024/05/19 13:56
题意:给定数列A,问有多少个数列B满足一下条件
1.1<=Bi<=Ai
2.对于任意 1<=l<=r<=len(A) , 有gcd(Bl,Bl+1,……Br)>=2
全是就是gcd(B)>=2
思路:
实在太弱了,多校中写不出来,就想着找最小的Ai,然后遍历每个gcd遍历一遍数组A, 1E10的复杂度 会爆
看了大佬们的博客,
有些还用了莫比乌斯反演
有些没用直接求,再容斥原理去重
一直在想为什么将数列中的数字转化为权值数组,即存值小于X的数有多少个可以把 n^2 降到 nlogn
因为 j*i-1~j*i+i-1的数值除i得到的结果都是相同的
枚举 gcd后 复杂度一共为 n/1 + n/2 + n/3 + ...........=nlogn
容斥这一块
不用莫比乌斯函数的话,普通的容斥原理,ans[a]-=(ans[2a]+ans[3a]+ans[4a]+......),得到的答案才是gcd=a对答案的贡献
同样ans[2a]-=(ans[4a]+ans[6a]+ans[8a]+......)
显然要先得到gcd=2a的ans[2a]才能得到 gcd=a的ans[a],因此要从后往前遍历容斥
#include<bits/stdc++.h>#define N 1000000007using namespace std;long long f(long long a,long long b){long long ans=1;while(b){if(b&1) ans=(ans*a)%N;a=(a*a)%N;b>>=1;}return ans; } int num[100009];long long pp[100009];long long ans[100009];int main(){int k=1;int t,len,a;scanf("%d",&t);while(t--){scanf("%d",&len);memset(num,0,sizeof(num));for(int i=0;i<len;i++){scanf("%d",&a);num[a]++;}for(int i=1;i<=100000;i++)num[i]+=num[i-1];bool flag=false;for(int i=2;i<=100000;i++)//枚举gcd if(flag) ans[i]=0;else{if(num[i-1]>0){flag=true;ans[i]=0;continue;}ans[i]=1;for(int j=1;j*i<=100000;j++){ans[i]=ans[i]*(f(j,num[min((j+1)*i-1,100000)] - num[j*i-1]))%N;}}long long p=0;for(int i=100000;i>=2;i--){for(int j=2*i;j<=100000;j+=i){ans[i]-=ans[j];ans[i]=(ans[i]%N+N)%N;} p = (p+ans[i])%N; }printf("Case #%d: %lld\n",k++,p);}return 0;}
莫比乌斯函数
这里分享两个博客感觉挺不错的
莫比乌斯函数
读贾志鹏线性筛有感 (莫比乌斯函数的应用)
根据容斥原理,我们知道,ans = +[k=一个不同素数之积 时对答案的贡献]
= -[k=两个不同素数之积 时对答案的贡献]
= +[k=三个不同素数之积 时对答案的贡献]
比如上面那个图,ans=1*F[2]+1*F[3]+1*F[5]+(-1)*F[6]+(-1)*F[10]+(-1)*F[15]+ 1*F[30]+。。。。。。
刚好是莫比乌斯函数的相反数
感觉就像一位大佬说的那样 (-1)^K ,n=p1p2p3……pk 这实际上就是在容斥
#include<bits/stdc++.h> using namespace std;#define N 1000000007using namespace std;long long f(long long a,long long b){long long ans=1;while(b){if(b&1) ans=(ans*a)%N;a=(a*a)%N;b>>=1;}return ans; } int mu[100005];int num[100005];bool book[100005];int prime[100005]; void init() //莫比乌斯函数表 { memset(book,false,sizeof(book)); mu[1] = 1; int cnt = 0; for(int i = 2;i <= 100000;i++) { if(!book[i]) //第一个遇见的素数 { prime[cnt++] = i; //素数表 mu[i] = -1; } for(int j = 0;j < cnt && i*prime[j] <=100000;j++) { book[i*prime[j]] = true; if(i % prime[j]) mu[i*prime[j]] = -mu[i]; else { mu[i*prime[j]] = 0; break; } } }}int main(){int k=1;init();int t,len,a,Min;scanf("%d",&t); long long ans,temp; while(t--){Min=100000;scanf("%d",&len);memset(num,0,sizeof(num));for(int i=0;i<len;i++){scanf("%d",&a);num[a]++;Min=min(Min,a);}for(int i=1;i<=100000;i++)num[i]+=num[i-1];ans=0;for(int i=2;i<=Min;i++){if(!mu[i]) continue;temp=1;for(int j=1;j*i<=100000;j++)temp=temp*(f(j,num[min((j+1)*i-1,100000)] - num[j*i-1]))%N;ans=ans-mu[i]*temp; //莫比乌斯函数相反数 ans=(ans%N+N)%N;}printf("Case #%d: %lld\n",k++,ans);}return 0;}
- HDU-6053 TrickGCD 前缀和数组,莫比乌斯函数
- HDU 6053 TrickGCD(莫比乌斯反演+前缀和)
- hdu 6053TrickGCD(线性筛+莫比乌斯函数+前缀和)
- 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(容斥,分段,莫比乌斯函数)
- Linux_入门之虚拟机的全自动安装
- Android 三方登录
- c# android开发软件安装及环境配置
- 设计模式——观察者模式
- IntelliJ IDEA 的安装和破解
- HDU-6053 TrickGCD 前缀和数组,莫比乌斯函数
- 海量数据处理~
- 荀子 《劝学》
- loadrunner 在win10的那些事1
- 简单轮播图JS
- 【Java笔记】创建Class对象的三种常用办法和Class单例的测试
- 机器学习第二周--Multiple features & Normal equation
- 关于jquery的obj.click()、和obj.on()以及行内的onclick事件
- HDU1248 寒冰王座