D. CGCDSSQ(gcd性质)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D. CGCDSSQ(gcd性质)相关的知识,希望对你有一定的参考价值。

link

考虑当 l l l作为子数组的左端点, 随着 r r r的增大, [ l , r ] [l,r] [l,r]的gcd是不增的

于是gcd会从 a [ l ] a[l] a[l]慢慢变小, 而且发现变小的次数不会很多, g c d gcd gcd变小后仍是自己的因子

考虑到 a [ l ] a[l] a[l]质因数分解后只有几十个质因子, 推测出变小次数只有几十次

也就是随着r的增大, 大部分时间gcd都是不变的

所以对于每个l, 找到会引起变化的关键点r1,r2,r3…即可


这样不太好找, 考虑固定r, 找之前会引起变小的l1,l2,l3…

这样我们可以利用r-1的那些答案.

也就是说如果存在一个x使得[x,r]和[x+1,r]的gcd不同, 必然存在

[x,r-1]和[x+1,r-1]的gcd不同. 因为[x+1,r]的gcd肯定是[x+1,r-1]的因子。

#include <iostream>
#include <map>
#include <vector>
using namespace std;
const int maxn = 3e5+10;
int n,a[maxn],q;
map<int,long long>mp;
vector<int>vec[maxn];
int gcd(int a,int b)
    return b==0?a:gcd(b,a%b);

void solve(int id)
    int now = a[id], pos = id;
    for(int i=0;i<vec[id].size();i++)
        mp[now] += pos-vec[id][i];
        pos = vec[id][i];
        now = gcd( now,a[pos] );
    
    mp[now] += pos;

int main()
    cin >> n;
    for(int i=1;i<=n;i++)   cin >> a[i];
    for(int i=1;i<=n;i++)
        int now = a[i], ri = i;
        if( gcd(now,a[i-1]) != now )
            vec[i].push_back( i-1 ), now = gcd( now,a[i-1] );
        for(int j=0;j<vec[i-1].size();j++)
            int le = vec[i-1][j];
            if( gcd( now,a[le] ) != now )
                vec[i].push_back(le),now = gcd( now,a[le] );
        
    
    for(int i=1;i<=n;i++)   solve( i );
    int q; cin >> q;
    while( q-- )
        int x; cin >> x;
        cout << mp[x] << endl;
    

以上是关于D. CGCDSSQ(gcd性质)的主要内容,如果未能解决你的问题,请参考以下文章

D. CGCDSSQ(gcd性质)

D. CGCDSSQ (gcd&ST表)

CGCDSSQ

Codeforces 475D CGCDSSQ 区间gcd值

Codeforces475D - CGCDSSQ

Codeforces 338 D. GCD Table