【题目描述】
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; }