Sum Of Gcd HDU - 4676(莫队)

本文介绍了一种解决区间GCD求和问题的方法,并通过优化减少计算复杂度。使用线性筛法预处理欧拉函数与因数分解,结合分块思想进行区间查询优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given you a sequence of number a 1, a 2, …, a n, which is a permutation of 1…n.
You need to answer some queries, each with the following format:
Give you two numbers L, R, you should calculate sum of gcd(a[i], a[j]) for every L <= i < j <= R.
Input
First line contains a number T(T <= 10),denote the number of test cases.
Then follow T test cases.
For each test cases,the first line contains a number n(1<=n<= 20000).
The second line contains n number a 1,a 2,…,a n.
The third line contains a number Q(1<=Q<=20000) denoting the number of queries.
Then Q lines follows,each lines contains two integer L,R(1<=L<=R<=n),denote a query.
Output
For each case, first you should print “Case #x:”, where x indicates the case number between 1 and T.
Then for each query print the answer in one line.
Sample Input
1
5
3 2 5 4 1
3
1 5
2 4
3 3
Sample Output
Case #1:
11
4
0
把自己蠢哭了,智障去每次去dfs一个数的因子,直接预处理存起来不就好了嘛,预处理第一个询问居然直接去暴力,对自己无语啊。。。
优化版:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bitset>
#include<vector>
#define N 20500
#define INF 10000000000
#define mod 1000000007
using namespace std;
typedef long long  ll;
vector<int> factor[20005];
int phi[N];
void init()
{
    for(int i=0;i<N;i++)
        phi[i]=i;
    for(int i=2;i<N;i++)
    {
        if(phi[i]==i)
        {
            for(int j=i;j<N;j+=i)
                phi[j]-=phi[j]/i;
        }
    }
    for(int i=1;i<=20000;i++)
        for(int j=i;j<=20000;j+=i)
        factor[j].push_back(i);

}
int block[N];
struct node
{
    int l,r;
    int index;
}query[N];
ll ans[N];
int a[N];
int cmp(node x1,node x2)
{
    if(block[x1.l]==block[x2.l])
        return x1.r<x2.r;
    return block[x1.l]<block[x2.l];
}
int cnt[N];
int curL,curR;
ll curAns;
void add(int x)
{
    for(int i=0;i<factor[x].size();i++)
        {
            int num=factor[x][i];
            curAns+=phi[num]*cnt[num];
            cnt[num]++;
        }
}
void sub(int x)
{
    for(int i=0;i<factor[x].size();i++)
        {
            int num=factor[x][i];
            cnt[num]--;
            curAns-=phi[num]*cnt[num];
        }
}
void work(int L,int R)
{
    while(curL<L)
    {
        sub(a[curL]);
        curL++;
    }
    while(curL>L)
    {
        curL--;
        add(a[curL]);
    }
    while(curR>R)
    {
        sub(a[curR]);
        curR--;
    }
    while(curR<R)
    {
        curR++;
        add(a[curR]);
    }
}
int main()
{
    init();
    int t,n;
    scanf("%d",&t);
    int cal=1;
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        scanf("%d",&n);
        int limit=(int)sqrt(n);
        for(int i=1;i<=n;i++)
            block[i]=(i-1)/limit;
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&query[i].l,&query[i].r);
            query[i].index=i;
        }
        sort(query+1,query+1+m,cmp);
        curAns=0;
        for(int i=query[1].l;i<=query[1].r;i++)
            add(a[i]);
        ans[query[1].index]=curAns;
        curL=query[1].l;
        curR=query[1].r;
        for(int i=2;i<=m;i++)
        {
            work(query[i].l,query[i].r);
            ans[query[i].index]=curAns;
        }
        printf("Case #%d:\n",cal++);
        for(int i=1;i<=m;i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}

智障的版本:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bitset>
#include<vector>
#define N 20500
#define INF 10000000000
#define mod 1000000007
using namespace std;
typedef long long  ll;
vector<int> prime;
int phi[N];
void init()
{
    for(int i=0;i<N;i++)
        phi[i]=i;
    for(int i=2;i<N;i++)
    {
        if(phi[i]==i)
        {
            prime.push_back(i);
            for(int j=i;j<N;j+=i)
                phi[j]-=phi[j]/i;
        }
    }
}
int block[N];
struct node
{
    int l,r;
    int index;
}query[N];
int ans[N];
int a[N];
int cmp(node x1,node x2)
{
    if(block[x1.l]==block[x2.l])
        return x1.r<x2.r;
    return block[x1.l]<block[x2.l];
}
int gcd(int a,int b)
{
    return a%b==0?b:gcd(b,a%b);
}
int cnt[N];
int curAns,curL,curR;
int fac[100];
int e[100];
int k;
void getFac(int x)
{
    k=0;
    for(int i=0;prime[i]*prime[i]<=x;i++)
    {
        if(x%prime[i]==0)
        {
            fac[k]=prime[i];
            e[k]=0;
            while(x%prime[i]==0)
            {
                x/=prime[i];
                e[k]++;
            }
            k++;
        }
    }
    if(x>1)
    {
        fac[k]=x;
        e[k]=1;
        k++;
    }
}
int state;
void dfs(int cur,int temp)
{
    if(cur==k)
    {
        //cout<<temp<<endl;
        if(state==0)
        {
            cnt[temp]--;
            curAns-=phi[temp]*cnt[temp];
        }
        else
        {
            curAns+=phi[temp]*cnt[temp];
            cnt[temp]++;
        }
        return ;
    }
    dfs(cur+1,temp);
    int c=temp;
    for(int i=1;i<=e[cur];i++)
    {
        c*=fac[cur];
        dfs(cur+1,c);
    }

}
void dfs2(int cur,int temp)
{
    if(cur==k)
    {
        cnt[temp]++;
        return ;
    }
    dfs2(cur+1,temp);
    int c=temp;
    for(int i=1;i<=e[cur];i++)
    {
        c*=fac[cur];
        dfs2(cur+1,c);
    }

}
void work(int L,int R)
{
    while(curL<L)
    {
        state=0;
        getFac(a[curL]);
        dfs(0,1);
        curL++;
    }
    while(curL>L)
    {
        state=1;
        curL--;
        getFac(a[curL]);
        dfs(0,1);
    }
    while(curR>R)
    {
        state=0;
        getFac(a[curR]);
        dfs(0,1);
        curR--;
    }
    while(curR<R)
    {
        state=1;
        curR++;
        getFac(a[curR]);
        dfs(0,1);
    }
}
int main()
{
    init();
    int t,n;
    scanf("%d",&t);
    int cal=1;
    while(t--)
    {
        memset(cnt,0,sizeof(cnt));
        scanf("%d",&n);
        int limit=(int)sqrt(n);
        for(int i=1;i<=n;i++)
            block[i]=(i-1)/limit;
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        int m;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&query[i].l,&query[i].r);
            query[i].index=i;
        }
        sort(query+1,query+1+m,cmp);
        curAns=0;
        for(int i=query[1].l;i<=query[1].r;i++)
        {
            getFac(a[i]);
            dfs2(0,1);
            for(int j=i+1;j<=query[1].r;j++)
                curAns+=gcd(a[i],a[j]);
        }
        ans[query[1].index]=curAns;
        curL=query[1].l;
        curR=query[1].r;
        for(int i=2;i<=m;i++)
        {
            work(query[i].l,query[i].r);
            //cout<<curL<<" "<<curR<<endl;
            /*for(int i=1;i<=5;i++)
                cout<<cnt[i]<<" ";
            cout<<endl;*/
            ans[query[i].index]=curAns;
        }
        printf("Case #%d:\n",cal++);
        for(int i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值