[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

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;
}

原文地址:https://www.cnblogs.com/Vanisher/p/9136020.html