Description
Input
第一行输入一个正整数T(T<=85),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1<=n,m<=2000),表示序列的长度。
第二行包含n个正整数,表示a[0],a[1],…,an-1。
第三行包含m个正整数,表示b[0],b[1],…,bm-1。
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
HINT
Source
Claris出的论文题.
卡常数,要求O(1) gcd
毁我青春,颓我人生.
在写这个题的过程中收了最少10个弗拉格.
我真是弗拉格大师,连立带收,一条龙服务.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 1000000
#define GET (ch>='0'&&ch<='9')
using namespace std;
int T,n,m,a[2010],b[2010];
unsigned ans;
int t=1000,maxn=1000000;
int d[MAXN+10][4];
int Gcd[1010][1010];
int prime[200000],top;
bool not_prime[MAXN+10];
void check()
{
for (int i=0;i<=t;i++) Gcd[0][i]=Gcd[i][0]=Gcd[i][i]=i;
for (int i=2;i<=t;i++) for (int j=1;j<i;j++) Gcd[i][j]=Gcd[j][i]=Gcd[i-j][j];
d[1][0]=d[1][1]=d[1][2]=1;
for (int i=2;i<=maxn;++i)
{
if (!not_prime[i]) prime[++top]=i,d[i][0]=i,d[i][1]=d[i][2]=1;
for (int j=1;j<=top&&i*prime[j]<=maxn;++j)
{
int tmp=i*prime[j];not_prime[tmp]=1;
d[tmp][0]=d[i][0];d[tmp][1]=d[i][1];d[tmp][2]=d[i][2];
if (d[tmp][0]*prime[j]<=t) d[tmp][0]*=prime[j];
else if (d[tmp][1]*prime[j]<=t) d[tmp][1]*=prime[j];
else d[tmp][2]*=prime[j];
if (i%prime[j]==0) break;
}
}
}
inline void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
inline int Getgcd(int x,int y)
{
if (!x||!y) return x+y;
int ret=1,tmp,temp;
for (int i=0;i<3;++i)
{
tmp=d[x][i];
if (tmp<=t) temp=Gcd[tmp][y%tmp];
else if (y%tmp==0) temp=tmp;
else temp=1;
ret*=temp;y/=temp;
}
return ret;
}
int main()
{
check();
for (in(T);T;T--)
{
ans=0;in(n);in(m);
for (int i=0;i<n;++i) in(a[i]);
for (int j=0;j<m;++j) in(b[j]);
for (int i=0;i<n;++i) for (int j=0;j<m;++j) ans+=Getgcd(a[i],b[j])^i^j;
printf("%u\n",ans);
}
}