2019年华南理工大学程序设计竞赛(春季赛) H Parco_Love_GCD(思维)

链接: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

 

你可能感兴趣的:(思维,莫队)