Bayan 2015 Contest Warm Up, problem: (D) CGCDSSQ

Bayan 2015 Contest Warm Up, problem: (D) CGCDSSQ

题意:q次询问x,问存在多少组 [ l , r ] [l,r] 区间使得 g c d ( a l , a l + 1 , a r ) = x gcd(a_l,a_{l+1},……a_r)=x

个人想法:极像线段树的题面(不知道能不能做反正不会……
我的想法从每个数字开始遍历,如果 g c d [ l , r ] = 1 , g c d [ l , r + 1 ] gcd[l,r]=1,则gcd[l,r+1] 肯定=1,所以此时直接break,往gcd为1的map上加

但是其实最坏情况就是有很多个连续数字是相等的情况,这样就会一直遍历下去达到 O ( n 2 ) O(n^2) 的复杂度…所以直接TLE死掉了

错误代码:(小朋友请勿模仿

int gcd(int a,int b){ return b?gcd(b,a%b):a;}
map<int ,ll > M;
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    rep(i,1,n)scanf("%d",&a[i]);
    rep(i,1,n)
    {
        M[a[i]]++;
        int g=a[i];
        int j=i+1;
        while(j<=n&&g!=1)
        {
            g=gcd(g,a[j]);
            M[g]++;
            j++;
        }
        if (n-j+1>=0)M[1]+=(n-j+1);
    }
    int m,x;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&x);
        WW(M[x]);
    }
    return 0;
}

大神思路:考虑到 1 a i 1 0 9 1\leq a_i \leq 10^9 ,所以每个数字的gcd不会超过31, i + 1 i+1 位置的gcd贡献就是从 i i 位置的贡献基础上来的,所以可以递归求解,这个递归求解加上map的使用简直是无敌

正解:

map<int, ll> ans;
map<int, ll> now;
map<int, ll> pre;
map<int, ll>::iterator it;
int a[maxn];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main()
{
    int n;
    ans.clear();
    scanf("%d",&n);
    rep(i,1,n)scanf("%d",&a[i]);
    rep(i,1,n)
    {
        swap(pre,now);
        now.clear();
        for (it=pre.begin();it!=pre.end();it++)
        {
            now[gcd(it->first,a[i])]+=it->second;
        }
        now[a[i]]++;//自身也可以单独造成贡献
        for (it=now.begin();it!=now.end();it++)
        {
            ans[it->first]+=it->second;
        }
    }
    int q,x;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d",&x);
        WW(ans[x]);
    }
    return 0;
}
发布了109 篇原创文章 · 获赞 7 · 访问量 6048

猜你喜欢

转载自blog.csdn.net/w_udixixi/article/details/101456679