• BZOJ4454: C Language Practice


    Description

    Input

    第一行输入一个正整数T(T<=85),表示测试数据的组数。
    每组数据第一行包含两个正整数n,m(1<=n,m<=2000),表示序列的长度。
    第二行包含n个正整数,表示a[0],a[1],...,a[n-1](0<=a[i]<=1000000)。
    第三行包含m个正整数,表示b[0],b[1],...,b[m-1](0<=b[i]<=1000000)。

    Output

    对于每组数据输出一行一个整数,即答案。

    Sample Input

    3
    3 2
    5 9 6
    3 4
    2 2
    8 9
    0 6
    1 1
    9
    6

    Sample Output

    6
    22
    3
     
    传说中的O(n)-O(1)求gcd算法。
    这个算法基于这样一个定理:
    对于一个正整数x,x一定可以分解成x1*x2*x3的形式。其中xi满足要么小于等于sqrt(x),要么是一个素数。

    然后整个算法分为两步:
    1.预处理出1到N所有数的分解式与1到sqrt(N)内两两数的gcd。
    2.对于每个x,y,O(1)回答gcd(x,y)。
     
    预处理过程
    预处理1到sqrt(N)内两两数的gcd可以递推。
    预处理1到N所有数的分解式的话可以线性筛弄出每个数x最小的质因子p,再根据p的分解式得到x的分解式。
     
    询问过程
    因为xi要么<=sqrt(N)要么是一个素数,根据这个性质就可以写出代码:
    int SIZE=(int)sqrt(N);
    int ans=1,d;
    for(int i=0;i<3;i++)  {
        if(x[i]<=SIZE) d=gcd[x[i]][y%x[i]];
        else if(y%x[i]==0) d=x[i];
        else d=1;
        ans=ans*d;y=y/d;
    }
    

    正确性显然。

    全代码:

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=1000010;
    int g[1010][1010],d[maxn],pri[maxn/10],cnt;
    bool vis[maxn];
    int A[maxn],B[maxn],C[maxn];
    void init(int n) {
        rep(i,0,1005) rep(j,0,i) {
            if(!i||!j) g[i][j]=i+j;
            else g[i][j]=g[j][i%j];
        }
        rep(i,0,1005) rep(j,i+1,1005) g[i][j]=g[j][i];
        d[1]=1;
        rep(i,2,n) {
            if(!vis[i]) pri[++cnt]=i,d[i]=i;
            rep(j,1,cnt) {
                if(i*pri[j]>n) break;
                vis[i*pri[j]]=1;
                if(i%pri[j]==0) {d[i*pri[j]]=d[i];break;}
                d[i*pri[j]]=pri[j];
            }
        }
        A[1]=B[1]=C[1]=1;
        rep(i,2,n) {
            int j=i/d[i];A[i]=A[j];B[i]=B[j];C[i]=C[j];
            if(A[i]*d[i]<=1000) A[i]*=d[i];
            else if(B[i]*d[i]<=1000) B[i]*=d[i];
            else C[i]*=d[i];
        }
    }
    int X[3];
    int gcd(int x,int y) {
        if(!x||!y) return x+y;
        if(x<=1000&&y<=1000) return g[x][y];
        int c=0;
        if(A[x]!=1) X[c++]=A[x];
        if(B[x]!=1) X[c++]=B[x];
        if(C[x]!=1) X[c++]=C[x];
        int ans=1,d;
        rep(i,0,c-1) {
            if(X[i]<=1000) d=g[X[i]][y%X[i]];
            else if(y%X[i]==0) d=X[i];
            else d=1;
            ans*=d;y/=d;
        }
        return ans;
    }
    int n,m,a[2010],b[2010];
    int main() {
        init(1000000);
        dwn(T,read(),1) {
            n=read();m=read();unsigned int ans=0;
            rep(i,0,n-1) a[i]=read();
            rep(i,0,m-1) b[i]=read();
            rep(i,0,n-1) rep(j,0,m-1) ans+=gcd(a[i],b[j])^i^j;
            printf("%u
    ",ans);
        }
        return 0;
    }
    

      

     
  • 相关阅读:
    学习java第20天
    学习java第19天
    学习java第18天
    学习java第17天
    学习java第16天
    java架构师学习路线-Web分布式开发框架概述
    java架构师学习路线-并发编程的概念
    java架构师学习路线-Java系统中的微服务框架
    java架构师学习路线-HashMap的知识点总结归纳
    java架构师学习路线-Java并发编程的五种状态和两种创建方式
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5316963.html
Copyright © 2020-2023  润新知