zoukankan      html  css  js  c++  java
  • [学习笔记]基于值域预处理的快速 GCD

    江湖人称 \(O(1)gcd\) 的操作。

    我们用线性筛处理,那么我们可以把大多数的分解成不大于\(O(\sqrt n)\)的数的乘积
    如果分解出来大于\(O(\sqrt n)\),其一定是一个质数。
    我们具体方法:
    我们先找到\(x\)的最小质因子 \(p\) ,并得到 \(\frac{x}{p}\) 的分解,然后把 \(p\) 乘到最小的数上。

    证明为什么是对的。

    考虑归纳法。

    我们证明把 \(p\) 乘上最小的数其结果小于 \(\sqrt n\)

    则有\(\frac{n}{p}\) 的分解最小的数一定小于\(a \leq \sqrt[3]{\frac{n}{p}}\)

    所以有 \(a \times p \leq \sqrt[3]{\frac{n}{p}} \times p\)

    \(p > \sqrt[4]{n}\),则分解出的数为其三个质因子。

    否则有 \(a \times p \leq \sqrt[3]{\frac{n}{\sqrt[4]{n}}} \times \sqrt[4]{n} = \sqrt n\)

    然后打一个\(O(\sqrt v)\)
    然后打一个\(O(\sqrt v) \times O(\sqrt v)\)的表。

    具体看代码。

    #include<bits/stdc++.h>
    #define ll long long
    #define mod 998244353
    #define N 5010
    #define V 1000010
    #define radio 1010
    
    int a[N],b[N],n,ans;
    
    int np[V],pri[V],cnt;
    
    int k[V][3];
    
    int _gcd[radio][radio];
    
    inline int gcd(int a,int b){
    	int g = 1;
    	for(int tmp,i = 0;i < 3;++i){
    		if(k[a][i] > radio){
    			if(b % k[a][i] == 0)
    			tmp = k[a][i];
    			else
    			tmp = 1;
    		}else{
    			tmp = _gcd[k[a][i]][b % k[a][i]];
    		}
    		b /= tmp;
    		g *= tmp;
    	}
    	return g;
    }
    
    int main(){
    	k[1][0] = k[1][1] = k[1][2] = 1;
    	np[1] = 1;
    //    for(int i = 2; i < V; i++) {
    //        if(!np[i]) pri[++cnt] = i, k[i][2] = i, k[i][1] = k[i][0] = 1;
    //        for(int j = 1; pri[j] * i < V; j++) {
    //            np[i * pri[j]] = 1;
    //            int *tmp = k[i * pri[j]];
    //            tmp[0] = k[i][0] * pri[j];
    //            tmp[1] = k[i][1];
    //            tmp[2] = k[i][2];
    //            if(tmp[1] < tmp[0]) std::swap(tmp[1], tmp[0]);
    //            if(tmp[2] < tmp[1]) std::swap(tmp[2], tmp[1]);
    //            if(i % pri[j] == 0) break;
    //        }
    //    }
    	for(int i = 2;i < V;++i){
    		if(!np[i])pri[++cnt] = i,k[i][2] = i,k[i][1] = k[i][0] = 1;
    		for(int j = 1;pri[j] * i < V && j <= cnt;++j){
    			np[i * pri[j]] = 1;
    			int *tmp = k[i * pri[j]];
    			tmp[0] = k[i][0] * pri[j];
    			tmp[1] = k[i][1];
    			tmp[2] = k[i][2];
    			if(tmp[1] < tmp[0])std::swap(tmp[1],tmp[0]);
    			if(tmp[2] < tmp[1])std::swap(tmp[2],tmp[1]);
    			if(i % pri[j] == 0)break;
    		}
    	}
    	for(int i = 1;i < radio;++i)_gcd[i][0] = _gcd[0][i] = i;
    	for(int _max = 1;_max < radio;_max ++ ){
    		for(int i = 1;i <= _max;++i)
    		_gcd[i][_max] = _gcd[_max][i] = _gcd[_max % i][i];
    	}
    // for(int i = 1; i <= 10; i++)
    //         for(int j = 1; j <= 10; j++) printf("gcd(%d, %d) = %d\n", i, j, _gcd[i][j]);
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", a + i);
        for(int i = 1; i <= n; i++) scanf("%d", b + i);
        for(int i = 1; i <= n; i++) {
            int now = 1, ans = 0;
            for(int j = 1; j <= n; j++) {
                now = 1ll * now * i % mod;
                ans = (ans + 1ll * gcd(a[i], b[j]) * now) % mod;
            }
            printf("%d\n", ans);
        }
        return 0;
    
    }
    
  • 相关阅读:
    第42天:焦点图
    第41天:匀速、缓动运动和图片无缝滚动
    第40天:字符串操作:截取字符串
    MyBatis一级缓存(转载)
    Mycat 做简单的读写分离(转载)
    ui设计的好网站(转载)
    Java面试常问的问题(转载)
    ios学习的博客地址
    策略模式
    dubbo框架的简单介绍
  • 原文地址:https://www.cnblogs.com/dixiao/p/15717520.html
Copyright © 2011-2022 走看看