分解质因数(线性筛)

https://ac.nowcoder.com/acm/contest/923/B

我真是个辣鸡,现在才知道线性筛,

思路:对于每个数字的阶乘,开一个一维数组记录每个数字出现的个数,先利用一维差分将每个数字的阶乘中出现都得数字累加个数,然后再利用线性筛中,已知每个数字的最小质因数是什么,在比较过程中,我们可以从大到小比较,如果发现对于同一个数字它的出现次数不同,我们可以把这个数字划分为两个数字的乘积形式(已知每个数字的最小质因数都是固定的),如果数字相同就不用管了,最后在遍历一遍看看是否每个位置的数字个数都相同就可以了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int v[maxn],prime[maxn];
int a[maxn],b[maxn];
int da[maxn],db[maxn];
void primes(int n)
{
    memset(v,0,sizeof(v));
    int m=0;
    for(int i=2; i<=n; i++)
    {
        if(v[i]==0)
        {
            v[i]=i;
            prime[++m]=i;
        }
        for(int j=1; j<=m; j++)
        {
            if(prime[j]>v[i]||prime[j]>n/i) break;
            v[i*prime[j]]=prime[j];
        }
    }
}
int main()
{
    primes(100000);
    int t;
    scanf("%d",&t);
    for(int it=1; it<=t; it++)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(da,0,sizeof(da));
        memset(db,0,sizeof(db));

        for(int i=1; i<=n; i++)
        {
            int t;
            scanf("%d",&t);
            if(t>1)
            {
                da[2]++;
                da[t+1]--;
            }
        }
        for(int i=1; i<=m; i++)
        {
            int t;
            scanf("%d",&t);
            if(t>1)
            {
                db[2]++;
                db[t+1]--;
            }
        }
        for(int i=2; i<=1e5; i++)
        {
            da[i]+=da[i-1];
            db[i]+=db[i-1];
            a[i]+=da[i];
            b[i]+=db[i];
        }
        for(int i=1e5; i>=2; i--)
        {
            if(a[i]!=b[i])
            {
                int zy1=i/v[i];
                int zy2=i/zy1;
                int ta=a[i];
                int tb=b[i];
                a[i]=b[i]=0;
                a[zy1]+=ta;
                a[zy2]+=ta;
                b[zy1]+=tb;
                b[zy2]+=tb;
            }
        }
        int flag=1;
        for(int i=2; i<=1e5; i++)
        {
            if(a[i]!=b[i])
            {
//            printf("%d %d\n",a[i],b[i]);
                flag=0;
                break;
            }
        }
        if(flag)
            printf("equal\n");
        else
            printf("unequal\n");
    }
}

原文地址:https://www.cnblogs.com/dongdong25800/p/11067710.html

时间: 2024-11-01 22:40:48

分解质因数(线性筛)的相关文章

【BZOJ-4514】数字配对 最大费用最大流 + 质因数分解 + 二分图 + 贪心 + 线性筛

4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 726  Solved: 309[Submit][Status][Discuss] Description 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数, 那么这两个数字可以配对,并获得 ci×cj 的价值. 一个数字只能参与一次配对,可以不参与配对. 在

Codeforces 893E Counting Arrays:dp + 线性筛 + 分解质因数 + 组合数结论

题目链接:http://codeforces.com/problemset/problem/893/E 题意: 共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6). 问你有多少种长度为y,乘积为x的整数数列.(可以有负数) 题解: 首先考虑数列只有正整数的情况. 将x分解质因数:x = ∑ a[i]*p[i] 由于x较大,所以要先用线性筛求出素数,再枚举素数分解质因数. 那么一个乘积为x的数列可以看做,将x的所有∑ p[i]个质因子,分配到了y个位置上. 设f(i)

质因数分解+欧拉筛+线性基

质因数分解: for(int i=2;i*i<=n;i++){ if(n%i==0) p.push_back(i); while(n%i==0) n/=i; } if(n!=1) p.push_back(n); 欧拉函数(线性筛): //欧拉函数 phi[x]代表[1,x]种与x互质的数的个数 void getphi() { phi[1]=1;int cnt=0; for(int i=2;i<=N;i++){ if(!vis[i]){prime[++cnt]=i;phi[i]=i-1;} fo

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

[原博客] 关于线性筛

埃氏筛法:从2开始,找到第一个没有被筛的数,把它标记为素数,然后把它的2倍.3倍……筛掉.复杂度O(nlogn). 改进的埃氏筛法:从2开始,找到第一个没有被筛的数x,把它标记为素数,然后把它的x倍.x+1倍……筛掉.复杂度O(nloglogn). 线性筛:保证每个数都被它的最小素因子筛掉.复杂度O(n). C++写起来大概是这样的: int mindiv[10000005],tot,prime[10000050]; int main(){ for(int i=2;i<=10000000;i++

【bzoj2795】[Poi2012]A Horrible Poem Hash+分解质因数

题目描述 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节.如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. 输入 第一行一个正整数n (n<=500,000),表示S的长度.第二行n个小写英文字母,表示字符串S.第三行一个正整数q (q<=2,000,000),表示询问个数.下面q行每行两个正整数a,b (1<=a<=b<=n),表示询问字符串S[a..b]的最短循环节长度. 输出 依次输出q行正整数,第i行的正整数对应第i

[zroj 51] [Pendulum] : 线性筛

问题描述 Evan 站在巨大的世纪钟摆前,观察着钟摆上方数字的塌缩.他发现,钟摆每摆动?次,上方的数字就会变成把它分解质因数后每一项的和.例如 12 =2 × 2 × 3,那么摆动一次后数字变成 2 + 2 + 3 = 7.现在,上方的数字正好是 x.Evan 还有 y 秒就要去新世界探索了,他想知道在钟摆摆动 y 次到他离开时,上方的数字是多少. 输入格式 第一行一个整数n,表示询问个数.后面n行每行两个整数x和y. 输出格式 n行,每行一个答案表示离开时上方的数字. 样例输入 2 5 3 2

数论线性筛总结 (素数筛,欧拉函数筛,莫比乌斯函数筛,前n个数的约数个数筛)

线性筛 线性筛在数论中起着至关重要的作用,可以大大降低求解一些问题的时间复杂度,使用线性筛有个前提(除了素数筛)所求函数必须是数论上定义的积性函数,即对于正整数n的一个算术函数 f(n),若f(1)=1,且当a,b互质时f(ab)=f(a)f(b),在数论上就称它为积性函数,若a,b不互质也满足的话则称作完全积性函数,下面说明每个筛子是怎么筛的. 最基础的是素数筛,其它三个筛都是以素数筛为前提 素数筛 void get_prime() { int pnum = 0; for(int i = 2;

线性筛素数、欧拉函数

判断一个数n是否是素数,众所周知可以用O(sqrt(n))的方法. 但是如果要求很多个数,这个方法就不太好了.(比如所有小于n的数,复杂度就是O(n1.5).) 埃拉托斯特尼筛法,大家都听说过.从2到n,去掉每个数的倍数,剩下来的就是质数. 不过这个方法会重复删除,比如6是2.3的倍数,会被删2次,因子越多,删的次数就越多. 改进之后的线性筛保证每个数只被最小的质因子删,所以是O(n)的. #include<cstdio> #include<cstring> #define MAX