码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces475D - CGCDSSQ

时间:2018-03-02 18:39:50      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:first   logs   isp   ace   math   gpo   取值   std   com   

Portal

Description

给出长度为\(n(n\leq10^5)\)的序列\(\{a_n\}\),给出\(q(q\leq3\times10^5)\)\(x\),对于每个\(x\),求满足\(gcd\{a_L...a_R\}\)的数对\((L,R)\)有多少个。

Solution

\(f[i][x]\)表示以\(i\)为左端点的区间中,\(gcd=x\)的有多少个。
由右到左进行转移,赋初值\(f[i][a_i]=1\)\[f[i][gcd(x,a_i)]=\sum f[i+1][x]\]因为对于以\(a_i\)为左端点的区间\(gcd\),最多只有\(loga_i\)种取值(每次\(gcd\)至少减小一半),所以第二维其实只有\(loga_i\)个有值。我们可以用map代替第二维,并滚动第一维。

时间复杂度\(O(nlog^2n)\)

Code

//CGCDSSQ
#include <cstdio>
#include <map>
using namespace std;
int const N=1e5+10;
int n,m,a[N];
map<int,long long> ans,f[2];
map<int,long long>::iterator it;
int gcd(int x,int y) {return x%y?gcd(y,x%y):y;}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int c=0;
    f[0][a[n]]=1; ans[a[n]]++;
    for(int i=n-1;i>=1;i--)
    {
        c^=1; f[c].clear(); f[c][a[i]]=1;
        for(it=f[c^1].begin();it!=f[c^1].end();it++)
            f[c][gcd(it->first,a[i])]+=it->second;
        for(it=f[c].begin();it!=f[c].end();it++) ans[it->first]+=f[c][it->first];
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int x; scanf("%d",&x);
        printf("%lld\n",ans[x]);
    }
    return 0;
}

P.S.

“以\(a_i\)为左端点的区间\(gcd\),最多只有\(loga_i\)种取值”感觉这个结论还蛮有用的。
第一次用map,感觉好厉害!Σ(????)?

Codeforces475D - CGCDSSQ

标签:first   logs   isp   ace   math   gpo   取值   std   com   

原文地址:https://www.cnblogs.com/VisJiao/p/8494287.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!