HDU 6053 TrickGCD
来源:互联网 发布:求生之路2不用网络 编辑:程序博客网 时间:2024/05/20 04:46
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6053
题意:
给出一个长度为N的序列A,让你求有同长度的满足下列要求的序列B一共有多少个。
* 对于每个Bi,满足1≤Bi≤Ai
* 对于每对( l , r ) (1≤l≤r≤n) , gcd(bl,bl+1…br)≥2
分析:
一开始我就想跟素数有关,所以我预处理了1e5内的素数表。
先比如对于一个数p(p不一定是素数),求gcd为p的倍数的答案,方法如下。
计算a数组中大小在k * p 到( k + 1 ) * p-1之间的数的个数( 1<=k<=mx/p,mx是a数组最大的数 ) 记为num,num就是所有ai / p ==k 的数的数量, 对于p来说就是可以变成 p ~ k * p 的数的个数 , 就是说把 k^num次乘到p的答案上。
举个例子, 比如有3个数 2 6 7,对于gcd是2的倍数的答案,
对于2 ~3 区间上有1个 ,有1个数可以是2
对于6~7 区间上有2个,有2个数 可以是2,4,6。
答案就是1 * 3 * 3 也就是 1 *(3^(2) )
计算gcd为pp的倍数的 满足要求所得的答案,就是下面的work函数。
ll work(ll pp){ ll x=max(mn/pp,1LL)*pp,sm=1;//mn是a数组的最小值。x是满足可以作为gcd的 pp的倍数 的最小值 while(x<=mx&&sm) { sm*=qpow(x/pp,(mp[x+pp-1]-mp[x-1]));//qpow是快速幂 求(x/pp)^(mp[x+pp-1]-mp[x-1]) 然后乘到答案上。 x+=pp;//x就是pp的倍数。 sm%=mod; } return sm;}
最初我只考虑了gcd为质数倍数的答案的和,
然而直接这样打有一个问题。就是比如你计算了gcd为2 的倍数 和3的倍数的答案。
这样你会计算多一个gcd为6的倍数的答案。
所以这里你就需要容斥一下来获得正确的答案。
想到这里,我惊讶的发现2*3*5*7*11*13*17>1e5,所以1e5内最多可以有6个不同质数相乘。
所以我开了一个vector,与处理了一下i个不同素数相乘的乘积(1<=i<=6)。
然后就直接处理答案。
我们加上奇数个素数相乘的数的倍数得到的答案,减掉偶数个素数相乘的数的倍数得到的答案。
得到的就是最终的答案。
ps:本来没准备写的来着,然而惊奇的看到我跟大佬们的做法貌似有点差异,于是记录一下。
代码:
#include<bits/stdc++.h>using namespace std;typedef long long ll;ll INF=0x3f3f3f3f,mod=1e9+7;ll p[10005],d[100005]= {0},hx=0;//p是存素数的数组,hx是素数个数,d是素筛的辅助数组ll a[100005],mx,mn;//a数组,a数组中最值ll mp[200005];// mp[i] 是 a数组中小于等于i的数的个数。ll qpow(ll aa,ll bb)//快速幂{ ll ans=1; while(bb) { if(bb%2) ans=(ans*aa)%mod; aa=(aa*aa)%mod; bb/=2; } return ans;}ll work(ll pp)//计算gcd为pp的倍数的b数组的个数{ ll x=max(mn/pp,1LL)*pp,sm=1; while(x<=mx&&sm) { sm*=qpow(x/pp,(mp[x+pp-1]-mp[x-1])); x+=pp; sm%=mod; } return sm;}vector<ll>v[15];//预处理k个不同素数相乘的1e5以内的数void dfs(ll dep,ll pos,ll sm){ v[dep].push_back(sm); for(int i=pos; i<hx; i++) { if(sm*p[i]<=100000) dfs(dep+1,i+1,sm*p[i]); else return ; }}int main(){ for(int i=2; i<=100000; i++) { if(d[i]==0) { p[hx++]=i; } for(int j=0; j<hx&&p[j]*i<=100000; j++) { d[p[j]*i]=1; } }//素数筛选 dfs(0,0,1); int T; scanf("%d",&T); ll num=1; for(int i=1;i<=6;i++) sort(v[i].begin(),v[i].end());//这边之前忘记sort,后面直接break就炸了,比赛结束后调试发现原来是这边忘记sort,泪~ while(T--) { memset(mp,0,sizeof(mp)); ll n; mx=0,mn=1e5; scanf("%I64d",&n); for(int i=0; i<n; i++) { scanf("%I64d",&a[i]); mp[a[i]]++; mx=max(mx,a[i]); mn=min(mn,a[i]); } for(int i=1; i<=200000; i++) { mp[i]=mp[i]+mp[i-1]; mp[i]%=mod; } ll ans=0; for(int i=1; i<=6; i++) { int len=v[i].size(),ff; ff=(i%2==1)?1:-1; for(int j=0; j<len; j++) { int id=v[i][j]; ll x=max(mn/id,1LL)*id,sm=1; if(mp[id-1]==0)// 没有比id小的数,才可能gcd是大于等于id的数。 { ans+=ff*work(id); ans%=mod; ans+=mod; ans%=mod; } else break; } } printf("Case #%I64d: %I64d\n",num++,ans); }}
- 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-6053TrickGCD
- HDU 6053 TrickGCD
- HDU 6053 TrickGCD
- HDU 6053 TrickGCD DP(筛法)
- HDU 6053 TrickGCD(枚举)
- TrickGCD HDU
- TrickGCD HDU
- hdu 6053 TrickGCD(筛法+容斥)
- hdu 多校 TrickGCD
- HDU 6503 TrickGCD
- DLL劫持漏洞原理
- 深度学习笔记---交叉熵代价函数
- sizeof 跟 strlen 区别
- ssm整合导入导出
- ARM NEON编程
- HDU 6053 TrickGCD
- hdu6055 Regular polygon【思维+几何基础】
- 图像恢复迭代算法的加速
- 记录一个下午撸的A星寻路算法
- [读书笔记] 《Python 机器学习》- 各种模型选择方法的封装
- 【STM32】 keil新建工程模板
- UVA 12661 Funny Car Racing
- Laravel文件上传
- 利用ThreadPoolManager管理多线程 Http通信工具