• 牛客寒假训练第四场-J


    线性筛+暴力分解质因数+快速幂

    题目传送门

    首先对于(gcd(x_1, x_2, ..., x_n))有两种解法

    1. 辗转相除法,每次用辗转相除法求两个数的gcd,然后用结果再和下一个数求gcd即可
    2. 对每个(x_i) 分解质因子,n个数的最大公倍数就是:n个数所有(公共质因子的最小次幂 )的积

    对于方法2,举个例子:

    (12 = 2^2*3)

    (8 = 2^3)

    (18=2*3^2)

    (10=2*5)

    那么这三个数的最大公因数就是:(2^{min(2,3,1,1)}*3^{min(1,0,2,0)}*5^{min(0,0,0,1)} = 2^1 = 2)


    由于((x^a)^b = x^{a*b})

    所以假设 (x_i)可以质数分解成为:(x_i = p_{i1}^{k_{i1}}* p_{i2}^{k_{i2}}*...* p_{it}^{k_{it}});其中(p_{ij})表示分解的质数, (k_{ij})表示该质数的幂

    (x_i^{b_i} = p_{i1}^{k_{i1} * b_i}* p_{i2}^{k_{i2}*b_i}*...* p_{it}^{k_{it}*b_i})

    其中质数分解,直接暴力分解即可。

    我们的任务就是找出每个质数最小的幂(没有这个质数,幂就是0),然后用快速幂相乘即可。

    需要注意的是,对任意一个数分解质因子时,要求出1-10000所有质数的幂,比如 (10= 2^1*3^0*5^1*7^0*11^0*...) ,因为这里的0次也是有用的,表示n个数该质因子最小幂次是0,不能省略掉。

    ac代码

    // 分解质因数,求每个数所有质因数及其幂次 
    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    const int mod = 1e9+7; 
    int cnt=0;
    int vis[10010]; //
    int x[10010], p[10010], prime[10010]; // prime存质数
    int num[10010]; // 存每个质数的最小幂次,初始化成0x7f7f7f7f; num[i]表示prime[i]的最小幂次
    int n;
    // 快速幂 
    ll ksm(int n, int k)
    {
    	ll ans = 1;
    	ll tot = n;
    	while(k){
    		if(k&1) ans=ans*tot%mod;
    		tot = tot*tot%mod;
    		k>>=1;
    	}
    	return ans%mod;
    }
    // 打印质数表 
    void table(int n)
    {
    	memset(vis, 0, sizeof(vis));
    	for(int i=2; i<=n; ++i){
    		if(!vis[i]) 
    			prime[cnt++]=i;
    		for(int j=0; j<cnt && 1ll*i*prime[j]<=n; ++j){
    			vis[i*prime[j]] = 1;
    			if(i%prime[j]==0) break;
    		}
    	}
    }
    int main()
    {
    	table(10000);
    	scanf("%d",&n);
    	for(int i=0; i<n; ++i){
    		scanf("%d", &x[i]); 
    	}
    	for(int i=0; i<n; ++i){
    		scanf("%d", &p[i]); 
    	}
    	memset(num, 0x7f7f7f7f, sizeof(num));
    	for(int i=0; i<n; ++i){
    		for(int j=0; j<cnt; ++j){ // 暴力分解质因数即可; 要分解出所有的质因数,包括幂次 为0的 
    //			if(x[i] == 1) break;
    //			if(x[i]%prime[j]!=0) continue;
    			int t=0;
    			while(x[i]%prime[j]==0) {
    				x[i]/=prime[j];
    				t++;
    			}
    			num[j] = min(num[j], t*p[i]);
    			
    		}
    	}
    	ll ans=1;
    	for(int i=0; i<cnt; ++i){
    		if(num[i]==0) continue;
    		ans = ans*ksm(prime[i], num[i])%mod;
    	}
    	printf("%lld", ans);
    }
    
    

    时间复杂度:(O(n))

  • 相关阅读:
    Unicode下CString(wchar_t)转换为 char*
    安装程序制作(转)
    STL头文件
    杭电2043 请大神帮我看看哪错了?谢谢了!
    杭电2046
    杭电2044
    实现winform中的treeview控件部分节点显示checkbox,部分节点不显示checkbox的功能
    实现将sqlserver2000的多张表导出到access,并压缩,并导入压缩的access文件到sqlserver2000
    从Excel中指定的sheet名称或索引读取数据到DataTable,以便用户更改sheet名称后仍能读取数据
    combobox控件实现多列显示
  • 原文地址:https://www.cnblogs.com/VanHa0101/p/14423927.html
Copyright © 2020-2023  润新知