莫隊算法,gcd(The sum of gcd,HDU 5381)

有一個小失誤,WA了很久。

轉移的順序應該是

①增加r

②減少l

③減少r

④增加l


否則可能會出現錯誤

比如想從[a,b]轉移到[c,d]

但是c<a,d<b,d<a

如果順序不對的話,按照我自己的算法,就會算錯。


代碼

#include<stdio.h>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 10010;

int n,Q;
int A[maxn];
int b[maxn];
vector<int>l[maxn][2];
vector<int>r[maxn][2];
vector<int>vec[2];

struct qr
{
    int l,r;
    int id;
    ll ans;
}QR[maxn];

bool cmp1(qr x,qr y)
{
    if(b[x.l]!=b[y.l]) return b[x.l]<b[y.l];
    else return x.r<y.r;
}

bool cmp2(qr x,qr y)
{
    return x.id<y.id;
}

void read()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",A+i);
        for(int j=0;j<2;j++)
        {
            l[i][j].clear();
            r[i][j].clear();
        }
    }
    scanf("%d",&Q);
    b[0]=sqrt(n);
    for(int i=1;i<=Q;i++)
    {
        scanf("%d %d",&QR[i].l,&QR[i].r);
        QR[i].id=i;
        b[i]=(i-1)/b[0]+1;
    }
}

int gcd(int a,int b)
{
    return !b?a:gcd(b,a%b);
}

void erase(int p)
{
    for(int i=p;i<(int)vec[0].size()-1;i++)
        for(int j=0;j<2;j++)
            vec[j][i]=vec[j][i+1];
    for(int j=0;j<2;j++)
        vec[j].resize(vec[j].size()-1);
}

void insert(int x,int y)
{
    for(int i=0;i<(int)vec[0].size();i++)
        if(vec[0][i]==x)
        {
            erase(i);
            break;
        }
    for(int j=0;j<2;j++)
        vec[j].resize(vec[j].size()+1);
    for(int i=vec[0].size()-2;i>=0;i--)
        for(int j=0;j<2;j++)
            vec[j][i+1]=vec[j][i];
    vec[0][0]=x;
    vec[1][0]=y;
    int GCD = vec[0][0];
    for(int i=1;i<(int)vec[0].size();i++)
    {
        GCD = gcd(GCD,vec[0][i]);
        if(GCD==1)
        {
            for(int j=0;j<2;j++)
                vec[j].resize(i+1);
            break;
        }
    }
}

void print()
{
    puts("---");
    for(int i=0;i<(int)vec[0].size();i++)
        printf("%d\n",vec[0][i]);
    puts("---");
}

void pre()
{
    vec[0].clear();
    vec[1].clear();
    for(int i=1;i<=n;i++)
    {
        int cur=i;
        int CUR=A[i];
        //print();
        for(int j=0;j<(int)vec[0].size();j++)
        {
            int VAL = vec[0][j];
            int POS = vec[1][j];
            VAL = gcd(VAL,CUR);
            if(CUR!=VAL)
            {
                CUR=VAL;
                cur=POS;
                l[i][0].push_back(CUR);
                l[i][1].push_back(cur);
            }
        }
        insert(A[i],i);
    }

    vec[0].clear();
    vec[1].clear();
    for(int i=n;i>=1;i--)
    {
        int cur=i;
        int CUR=A[i];
        for(int j=0;j<(int)vec[0].size();j++)
        {
            int VAL = vec[0][j];
            int POS = vec[1][j];
            VAL = gcd(VAL,CUR);
            if(CUR!=VAL)
            {
                CUR=VAL;
                cur=POS;
                r[i][0].push_back(CUR);
                r[i][1].push_back(cur);
            }
        }
        insert(A[i],i);
    }
}

void solve()
{
    read();
    pre();
    int le=1;
    int ri=0;
    ll ans=0;
    sort(QR+1,QR+1+Q,cmp1);
    for(int i=1;i<=Q;i++)
    {
        while(ri<QR[i].r)
        {
            ri++;
            int cur=ri;
            int CUR=A[ri];
            for(int j=0;j<(int)l[ri][0].size();j++)
            {
                int VAL = l[ri][0][j];
                int POS = l[ri][1][j];
                ans+=1ll*min(cur-POS,cur-le+1)*CUR;
                CUR=VAL;
                cur=POS;
                if(cur<le) break;
            }
            if(cur>=le) ans+=1ll*(cur-le+1)*CUR;
        }

        while(le>QR[i].l)
        {
            le--;
            int cur=le;
            int CUR=A[le];
            for(int j=0;j<(int)r[le][0].size();j++)
            {
                int VAL = r[le][0][j];
                int POS = r[le][1][j];
                ans+=1ll*min(POS-cur,ri-cur+1)*CUR;
                CUR=VAL;
                cur=POS;
                if(cur>ri) break;
            }
            if(cur<=ri) ans+=1ll*(ri-cur+1)*CUR;
        }

        while(ri>QR[i].r)
        {
            int cur=ri;
            int CUR=A[ri];
            for(int j=0;j<(int)l[ri][0].size();j++)
            {
                int VAL = l[ri][0][j];
                int POS = l[ri][1][j];
                ans-=1ll*min(cur-POS,cur-le+1)*CUR;
                CUR=VAL;
                cur=POS;
                if(cur<le) break;
            }
            if(cur>=le) ans-=1ll*(cur-le+1)*CUR;
            ri--;
        }

        while(le<QR[i].l)
        {
            int cur=le;
            int CUR=A[le];
            for(int j=0;j<(int)r[le][0].size();j++)
            {
                int VAL = r[le][0][j];
                int POS = r[le][1][j];
                ans-=1ll*min(POS-cur,ri-cur+1)*CUR;
                CUR=VAL;
                cur=POS;
                if(cur>ri) break;
            }
            if(cur<=ri) ans-=1ll*(ri-cur+1)*CUR;
            le++;
        }
        QR[i].ans=ans;
    }
    sort(QR+1,QR+1+Q,cmp2);
    for(int i=1;i<=Q;i++)
        printf("%lld\n",QR[i].ans);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--) solve();
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章