给定n,m,a[0..n-1],b[0..m-1],求sigma i=0..n-1 sigma j=0..m-1 gcd(a[i],b[j]) xor i xor j,多组数据
O(1000000)预处理将每个数分解为三个数之积,且这三个数中任一个满足为质数或小于1000,预处理小于1000的数两两的gcd,即可O(1)求gcd
#include<cstdio> int t,n,m; int a[2048],b[2048]; int g[1024][1024]; const int N=1000005; int v0[N],v1[N],v2[N],mp[N]={0,1}; bool isnp[1000002]={1,1}; int ps[100000],p=0; inline int read(){ register int x=0,c=getchar(); while(c>'9'||c<'0')c=getchar(); while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); return x; } inline int gcd(int a,int b){ while(b){int c=a;a=b;b=c%b;} return a; } int x[3]; inline int gcd1(int a,int b){ if(!a||!b)return a^b; if(a<=1000&&b<=1000)return g[a][b]; int pp=0; if(v0[a]!=1)x[pp++]=v0[a]; if(v1[a]!=1)x[pp++]=v1[a]; if(v2[a]!=1)x[pp++]=v2[a]; int ans=1,d; for(int i=0;i<pp;i++){ d=x[i]<=1000?g[x[i]][b%x[i]]:b%x[i]?1:x[i]; ans*=d; b/=d; } return ans; } int main(){ for(int i=0;i<=1000;i++)for(int j=i;j<=1000;j++)g[i][j]=g[j][i]=gcd(i,j); for(int i=2;i<=1000000;i++){ if(!isnp[i])ps[p++]=i,mp[i]=i; for(int j=0,k;(k=i*ps[j])<=1000000;j++){ isnp[k]=1; if(i%ps[j]==0){ mp[k]=mp[i]; break; } mp[k]=ps[j]; } } v0[1]=v1[1]=v2[1]=1; for(int i=2;i<=1000000;i++){ int j=i/mp[i]; v0[i]=v0[j];v1[i]=v1[j];v2[i]=v2[j]; if(v0[i]*mp[i]<=1000)v0[i]*=mp[i]; else if(v1[i]*mp[i]<=1000)v1[i]*=mp[i]; else v2[i]*=mp[i]; } t=read(); while(t--){ n=read(); m=read(); for(int i=0;i<n;i++)a[i]=read(); for(int i=0;i<m;i++)b[i]=read(); unsigned int ans=0; for(int i=0;i<n;i++)for(int j=0;j<m;j++)ans+=gcd1(a[i],b[j])^i^j; printf("%u\n",ans); } return 0; }