zoukankan      html  css  js  c++  java
  • [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;
    }
    

  • 相关阅读:
    Python并发(一)
    Python协程详解(二)
    Python协程详解(一)
    Python装饰器
    ●BZOJ 3676 [Apio2014]回文串
    ●POJ 3974 Palindrome(Manacher)
    ●BZOJ 1692 [Usaco2007 Dec]队列变换
    ●BZOJ 4698 Sdoi2008 Sandy的卡片
    ●BZOJ 4516 [Sdoi2016]生成魔咒
    ●BZOJ 3238 [Ahoi2013]差异
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136020.html
Copyright © 2011-2022 走看看