hdu5381

这道题大家都用莫队算法做的,如果一直[l,r],就能很快的求出[l+1,r],[l,r+1],[l-1,r]和[l,r-1],那么就可以用莫队算法。

如果下次需要莫队算法,需要修改的就是从[l,r]推出[l+1,r],[l,r+1],[l-1,r]和[l,r-1]这一块。针对不同题不同分析,其他地方大概相同。

代码参考自:http://blog.csdn.net/firenet1/article/details/47616365

其实,我觉得最酷的莫过于


说好的图片呢?只能这样了http://www.zhihu.com/question/24201454

(2015.10.4:今天才发现不是博客的问题,是自己不会上传图片的问题,还以为只要复制粘贴,就可以万事大吉,接着这个机会,由默念了一遍莫队算法大法好)


(今天早上吃的茄子馅的包子,一直听说辣,就没吃,但是今天去买的时候,没有牛肉馅的,又见很多人都买茄子馅的,想着虽然辣,味道应该不错吧,就尝试了一下,嗯,真的很好吃,辣度竟然在我能接受的范围内)

2015.8.29:

再看这道题的时候,想起了是用莫队算法,根据记忆中的小片断一点一点推出来,但是,记忆中错误的当成了a.l%length,想着这样明显不省力呀,为什么还那么快,结果看了代码以后,发现是/,这样就能解释通了。

(学校的排骨汤开卖了,土豆和香菇的还是很好吃,而且,肉比上学期要好吃的感觉,不知道是不是太久没吃到,这个月吃了好多呀,开学后得省钱了尴尬,没办法,恩格尔系数太大,得降降了。)


#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define N 10010

struct node{
    int l;
    int r;
    int id;
};
struct sign{
    int g;
    int num;
    sign(int tempg=0,int tempnum=0){
        g=tempg;
        num=tempnum;
    }
};
int numa[N];
long long int ansa[N];
struct node querya[N];
int length;
vector<sign> rrgcd,rlgcd,llgcd,lrgcd;

bool cmp(struct node a,struct node b){
    if(a.l/length==b.l/length){
        return a.r<b.r;
    }
    else{
        return a.l/length<b.l/length;
    }
}

int gcd(int a,int b){
    int c;

    while(b){
        c=a%b;
        a=b;
        b=c;
    }

    return a;
}

int main(){
    int t;
    int n;
    int q;

    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&numa[i]);
        }

        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&querya[i].l,&querya[i].r);
            querya[i].id=i;
        }
        for(length=0;length*length<=n;length++);
        sort(querya+1,querya+1+q,cmp);

        int kuainum=-1,RR=0;
        long long ansrr=0;
        for(int i=1;i<=q;i++){
            //printf("%d %d %d\n",i,querya[i].l,querya[i].r);
            if(querya[i].l/length!=kuainum){
                kuainum=querya[i].l/length;
                RR=(kuainum+1)*length-1;
                rrgcd.clear();
                rlgcd.clear();
                ansrr=0;
            }
            while(RR<querya[i].r){
                RR++;
                for(int j=0;j<rrgcd.size();j++){
                    rrgcd[j].g=gcd(rrgcd[j].g,numa[RR]);
                    ansrr+=(long long int)rrgcd[j].g*rrgcd[j].num;
                }
                rrgcd.push_back(sign(numa[RR],1));
                ansrr+=(long long int)numa[RR];

                int nowindex=0;
                for(int k=1;k<rrgcd.size();k++){
                    if(rrgcd[k].g==rrgcd[nowindex].g){
                        rrgcd[nowindex].num+=rrgcd[k].num;
                    }
                    else{
                        nowindex++;
                        rrgcd[nowindex]=rrgcd[k];
                    }
                }
                while(nowindex+1<rrgcd.size()){
                    rrgcd.pop_back();//因为gcd是单调减的,所以即使是按顺序加入,未排序,也是按照从大到小的顺序排的
                }

                if(rlgcd.size()==0){
                    //printf("%d %d\n",RR,numa[RR]);
                    rlgcd.push_back(sign(numa[RR],1));
                }
                else{
                    int tempid=rlgcd.size();
                    //printf("%d %d\n",tempid-1,rlgcd[tempid-1].g);
                    if(!(numa[RR]%rlgcd[tempid-1].g)){
                        rlgcd[tempid-1].num++;
                    }
                    else{//printf("wi shi da hao ren\n");
                        rlgcd.push_back(sign(gcd(rlgcd[tempid-1].g,numa[RR]),1));
                    }
                }
            }

            int LR=(kuainum+1)*length-1;
            LR=min(LR,querya[i].r);
            llgcd.clear();
            lrgcd.clear();
            long long int ansll=0;

            for(;LR>=querya[i].l;LR--){
                for(int j=0;j<llgcd.size();j++){
                    llgcd[j].g=gcd(llgcd[j].g,numa[LR]);
                    ansll+=(long long int)llgcd[j].g*llgcd[j].num;
                }
                llgcd.push_back(sign(numa[LR],1));
                ansll+=(long long int)numa[LR];

                int nowindex=0;
                for(int k=1;k<llgcd.size();k++){
                    if(llgcd[nowindex].g==llgcd[k].g){
                        llgcd[nowindex].num+=llgcd[k].num;
                    }
                    else{
                        nowindex++;
                        llgcd[nowindex]=llgcd[k];
                    }
                }
                while(nowindex+1<llgcd.size()){
                    llgcd.pop_back();
                }

                int tempid=lrgcd.size();
                if(tempid==0){
                    lrgcd.push_back(sign(numa[LR],1));
                }
                else{
                    int tempg=gcd(numa[LR],lrgcd[tempid-1].g);
                    if(tempg==lrgcd[tempid-1].g){
                        lrgcd[tempid-1].num++;
                    }
                    else{
                        lrgcd.push_back(sign(tempg,1));
                    }
                }
            }

            int tempid=querya[i].id;
            ansa[tempid]=ansll+ansrr;
            for(int j=0;j<lrgcd.size();j++){
                for(int k=0;k<rlgcd.size();k++){
                    ansa[tempid]+=(long long int)gcd(lrgcd[j].g,rlgcd[k].g)*lrgcd[j].num*rlgcd[k].num;
                }
            }
        }


        for(int i=1;i<=q;i++){
            printf("%lld\n",ansa[i]);
        }
    }

    return 0;
}

还有我自己看了题解和别人写的,没用莫对算法,我感觉能过,但是tle了。

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 10010
#define M 510

int num[N];
int gr[N][M];
int gcdnum[N][M];

int gcd(int a,int b){
    int c;

    while(b){
        c=a%b;
        a=b;
        b=c;
    }

    return a;
}

int main(){
    int t;
    int n;
    int q;
    int l,r;

    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }

        gr[n][0]=1;
        gr[n][1]=n;
        gcdnum[n][1]=num[n];

        for(int i=n-1;i>=1;i--){
            gr[i][0]=1;
            gr[i][1]=i;
            gcdnum[i][1]=num[i];
            for(int j=1;j<=gr[i+1][0];j++){
                int temploca=gr[i][0];
                int temp=gcd(num[i],gcdnum[i+1][j]);
                if(temp==gcdnum[i][temploca]){
                    gr[i][temploca]=gr[i+1][j];
                }
                else{
                    gr[i][0]++;
                    temploca++;
                    gr[i][temploca]=gr[i+1][j];
                    gcdnum[i][temploca]=temp;
                }
            }
        }

        //printf("wo shi da hao ren");
        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=gr[i][0];j++){
                printf("%d %lld %lldha\n",i,gr[i][j],gcdnum[i][j]);
            }
        }*/

        scanf("%d",&q);
        while(q--){
            scanf("%d%d",&l,&r);
            long long int ans=0;//计算过程中要强制转化为long long int

            for(int i=l;i<=r;i++){
                if(gr[i][1]<=r){
                    ans+=((long long int)gr[i][1]-i+1)*gcdnum[i][1];
                }
                else{
                    ans+=((long long int)r-i+1)*gcdnum[i][1];
                }

                for(int j=2;j<=gr[i][0];j++){
                    if(gr[i][j]<=r){
                        ans+=((long long int)gr[i][j]-gr[i][j-1])*gcdnum[i][j];
                    }
                    else{
                        ans+=((long long int)r-gr[i][j-1])*gcdnum[i][j];
                        break;
                    }
                }
            }

            printf("%lld\n",ans);
        }
    }
}


posted @ 2015-08-17 11:47  buzhidaohahaha  阅读(146)  评论(0编辑  收藏  举报