链接:https://ac.nowcoder.com/acm/contest/625/H
来源:牛客网
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
众所周知,在算法竞赛中,出题人对他出的题的难度往往存在错误的估计。比如出题人本想出个中等题,没想到却出成了简单题;本想出个自闭题,结果数据太水变成了签到题。因此,为了让一场比赛能有良好的体验,有一个靠谱的验题人是非常重要的。
CC出好题目后,便拿给小马哥看。不出所料,这些题目小马哥全都是看一眼就会做了。而且,小马哥觉得这些题对于参赛选手来说也太水了(5个签到题哦~)。为了避免发生全场十几个队AK这种紧急事态,小马哥决定把一道签到题改成简单题,于是便有了现在这个题目。
小马哥非常喜欢数论,尤其钟爱“最大公约数”(Greatest Common Divisor,简称GCD)这一概念,因此他打算出一道和GCD有关的题目。小马哥首先给出了含n个正整数的序列a1,a2,⋯,ana1,a2,⋯,an,然后让你考虑该序列的所有子区间的数对应的GCD值,也就是说考虑所有gcd(al,⋯,ar)gcd(al,⋯,ar)的值。显然,这样的值一共有n(n+1)2n(n+1)2个。一个中二出题人可能会让你求这n(n+1)2n(n+1)2数中第k大的数,但幸运的是,小马哥是个正经出题人,因此它只让你求这n(n+1)2n(n+1)2个数之和模109+7109+7的结果。
也就是要求下面这个式子:
ans=(∑nl=1∑nr=lgcd(al,⋯,ar))mod(109+7)ans=(∑l=1n∑r=lngcd(al,⋯,ar))mod(109+7)
小马哥在此预祝大家AK~
第一行是一个整数n (1≤n≤5×105)n (1≤n≤5×105),表示数的个数。
接下来一行给出n个整数,其中第i个整数aiai满足1≤ai≤1091≤ai≤109。
输出一行一个整数,表示ans的值。
示例1
复制
5
16 4 7 21 3
复制
72
题意:中问题意略
思路:第一反应是RMQ+二分。。。结果多了一个log然后就T了。。。
不难发现,当从a[r]开始,到a[r-1],a[r-2],...a[l]的gcd不变时(设为v[r]),我们就能一次统计答案了。由于gcd每一次减少至少/2,所以我们从每个r往前算的时候,最多有log(a[i])个不同的gcd。但是不能每次都一个一个往前找,我们用l[r]表示v[r]向前所能到达的最小下标,后面跳的时候l[i]就可以直接跳到l[l[i]-1]了。
代码:
#include
const int N=500010,P=1000000007;
int n,i,j,ans,a[N],l[N],v[N];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=n;i++)for(v[i]=a[i],j=l[i]=i;j;j=l[j]-1){
v[j]=gcd(v[j],a[i]);
while(l[j]>1&&gcd(a[i],v[l[j]-1])==gcd(a[i],v[j]))l[j]=l[l[j]-1];
ans=(1LL*v[j]*(j-l[j]+1)+ans)%P;
}
printf("%d",ans);
}
/*
5
16 4 7 21 3
72
*/
我在比赛的时候蠢蠢的用了HDU 5381 The sum of gcd的莫队做法(m=1,即只有一个1~n的查询),也能卡过。。。不过代码量和上面的解法差别可不是一点了。。。
代码:
#include
#include
#include
#include
#define ll long long
using namespace std;
#define N 500002
const ll mo=1e9+7;
struct node{
int l;
int r;
int id;
};
struct sign{
int g;
int num;
sign(int tempg=0,int tempnum=0){
g=tempg;
num=tempnum;
}
};
int numa[N];
long long int ansa[N];
struct node querya[N];
int length;
vector rrgcd,rlgcd,llgcd,lrgcd;
bool cmp(struct node a,struct node b){
if(a.l/length==b.l/length){
return a.r=querya[i].l;LR--){
for(int j=0;j