[JZOJ4586] Ned 的难题
2016-07-07 16:52
295 查看
Description
给出一个N个数的序列,求其中所有连续区间的最大公约数的乘积Solution
20%
N2暴力显然40%
只用在上面的基础上加上一句话,如果搜到的区间的gcd已经是1了就退出100%
有两种方法,一种是分解质因数乱搞的(我不会)讲另外一种比较简单的
我们设i,j,i向右枚举,j向左枚举(相当于反过来N2暴力)
那么显然1~i−1的所有区间的gcd都已经知道了
显然往左的gcd是单调不增的
并且我们有一个性质,区间中的值种数至多有logi2 种
为什么呢?
因为每一次求最小公约数,要么是相等,要么除掉了若干个质因数,最少也要除以2
所以我们可以在j向前枚举的时候,碰到相等的区间就可以直接跳过去,再用快速幂求对答案的贡献。
复杂度O(NlogN)
Code
#include<cstdio> #include<cstdlib> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #define fo(i,a,b) for(i=a;i<=b;i++) #define fod(i,a,b) for(i=a;i>=b;i--) #define mo 1000000009 #define LL long long using namespace std; int n; LL a[50005],ans,last[50005][2]; LL gcd(LL x,LL y) { LL r=x%y; x=y; y=r; while (r!=0) { r=x%y; x=y; y=r; } return x; } LL ksm(LL k,LL n) { if (n==1) return k; LL s=ksm(k,n/2); if (n%2) return(s*s%mo*k%mo); else return (s*s%mo); } int main() { int i,j; ans=1; cin>>n; fo(i,1,n) scanf("%lld",&a[i]); ans=a[1]; last[0][1]=1; last[1][0]=1; last[1][1]=a[1]; fo(i,2,n) { int c=a[i]; last[i][0]=i; last[i][1]=a[i]; j=i; while (j>0) { int p=j; j=last[j][0]-1; while (gcd(c,last[j][1])==c&&j>0) j=last[j][0]-1; last[p][0]=j+1; ans=(ans*ksm(c,p-j))%mo; c=gcd(c,last[j][1]); } } cout<<ans; }
相关文章推荐
- windows主机注册表解禁
- Java工程师成神之路
- RunLoop运行循环机制
- 学习笔记之TCP/IP协议结构
- hdu 5222(Tarjan求强连通分量+dfs)
- 带进度条的WebVeiw实现以及进度条和webview之间有空隙的解决方法
- 软件测试第一天
- informix 分页查询实现
- Python 语言及其应用 Chapter_7_Note 1 正则表达匹配
- 非常详细的 Docker 学习笔记 - OPEN 开发经验库
- 打印机工厂模式小记
- 线段树区间取max黑科技
- 基于scrapy框架的关于58同城招聘网站信息的爬取
- 16.7.7比赛总结
- C++基础8【难】 回顾:数组指针,函数指针,函数指针做函数参数 C语言多态
- Linux基础篇--GCC编译器
- 磁盘压缩卷只能压缩一半
- 设置TOMCAT启用GZIP压缩
- 【spring 配置文件】spring配置文件的解析
- Linux - tomcat