【题目描述】
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
3 2
5 9 6
3 4
2 2
8 9
0 6
1 1
9
6
Sample Output
6
22
3
22
3
HINT
注意:此题只有一个数据点。
Source
【题解】
这题需要O(1)回答gcd。
一个≤1000000的数,一定能拆成A*B*C的形式,其中A,B,C要么≤1000,要么为质数。
证明如下:
如果其中有一个为>1000的质数,显然成立。
否则分解因子并一个一个从前往后判断,能放就放。
反证一下,如果不能完全放入,设不能放的部分为D,那么有A,B,C,D任意两个相乘>1000。
根据均值不等式,当A=B=C=D时A*B*C*D取到最小值,这个值显然>1000000。
于是得证。
所以预处理1000以内的数的gcd,然后可以O(1)计算。
注意这题卡时间,优化的方法是:若A,B,C中有1,则直接跳过。
/* --------------
user Vanisher
problem bzoj-4454
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define T 1000000
# define t 1000
# define N 2010
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int d[T+1][3],p[T/10],pnum,a[N+1],b[N+1],g[t+1][t+1],n,m,X[3];
bool use[T];
int gcd(int x, int y){
if (y==0) return x;
if (x%y==0) return y;
else return gcd(y,x%y);
}
void pre(){
for (int i=0; i<=t; i++)
for (int j=0; j<=t; j++)
g[i][j]=gcd(i,j);
d[1][0]=d[1][1]=d[1][2]=1;
for (int i=2; i<=T; i++){
if (use[i]==false){
p[++pnum]=i;
d[i][0]=i; d[i][1]=1; d[i][2]=1;
}
for (int j=1; p[j]<=T/i&&j<=pnum; j++){
int k=p[j]*i;
use[k]=true;
d[k][0]=d[i][0]; d[k][1]=d[i][1]; d[k][2]=d[i][2];
if (d[k][0]*p[j]<=t) d[k][0]=d[k][0]*p[j];
else if (d[k][1]*p[j]<=t) d[k][1]=d[k][1]*p[j];
else d[k][2]=d[k][2]*p[j];
}
}
}
int solve(int x, int y){
if (x==0||y==0) return x+y;
if (x<=t&&y<=t) return g[x][y];
int now=1, les=y, c=-1;
if (d[x][0] != 1) X[++c] = d[x][0];
if (d[x][1] != 1) X[++c] = d[x][1];
if (d[x][2] != 1) X[++c] = d[x][2];
for (int i=0; i<=c; i++){
if (X[i]<=t){
int tmp=g[X[i]][les%X[i]];
les=les/tmp, now=now*tmp;
}
else {
if (les%X[i]==0)
les=les/X[i], now=now*X[i];
}
}
return now;
}
int main(){
pre();
int opt=read();
while (opt--){
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=ans+(solve(a[i],b[j])^i^j);
cout<<ans<<endl;
}
return 0;
}