题面

传送门

分析

1.暴力做法

首先先把每个数除以gcd(a1,a2…,an)gcd(a_1,a_2 \dots,a_n )gcd(a1​,a2​…,an​)

可以O(namax)O(n\sqrt {a_{max}})O(namax​​)的时间内分解出所有数的质因数,然后统计出现次数最多的质因数,设最多出现次数为xxx,然后把其他的数去掉就可以了,答案为n−xn-xn−x

例:

n=4,a={6,9,15,30}n=4,a=\{6,9,15,30\}n=4,a={6,9,15,30}

处理后a={2,3,5,10}a=\{2,3,5,10\}a={2,3,5,10}

2=22=22=2

3=33=33=3

5=55=55=5

10=2×510=2 \times 510=2×5

我们可以看出质因数2出现了2次,3出现了1次,5出现了2次

出现次数最多的质因数为2或5,均出现了2次

故答案为4-2=2

2.优化

可以看出算法的瓶颈在质因数分解,我们考虑如何优化质因数分解算法

这是一般的质因数分解算法

set<int>S;
for(int i=2; i<=x; i++) {
while(x%i==0 &&x != i) {
n/=i;
S.push(i);
}
if(x == i) {
S.push(i)
break;
}
}

该算法的时间复杂度为O(x)O(\sqrt x)O(x​)

问题在于该算法需要枚举能整除x的数,效率比较低,如果对于每个数x,我们知道能被整除x的最小质数minprime[x],算法的效率就可以提高了

那么如何求出minprime呢?

我们想到线性筛法的过程

for(int i=2; i<=n; i++) {
if(!vis[i]) {
prime[++k]=i;
}
for(ll j=1; j<=k&&(ll)i*prime[j]<=n; j++) {
minprime[(ll)i*prime[j]]=prime[j];
vis[(ll)i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}

其中的每个合数只会被筛一次,而prime[j]不正好是能整除i×prime[j]i\times prime[j]i×prime[j]的最小质数吗?

因此可以把线性筛改成这个样子

for(int i=2; i<=n; i++) {
if(!vis[i]) {
minprime[i]=i;
prime[++k]=i;
}
for(ll j=1; j<=k&&(ll)i*prime[j]<=n; j++) {
minprime[(ll)i*prime[j]]=prime[j];
vis[(ll)i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}

我们就求出了minprime,注意若p是质数,minprime[p]=p

然后可以写出分解质因数的算法


if(!vis[x]||x==1) {//如果是1或质数,直接返回
cnt[x]++;
return;
}
while(x>1) {
int t=minprime[x];
cnt[t]++;
while(x%t==0&&x!=1) {
x/=t;
} }

因为每次循环x至少要除以2,所以时间复杂度为O(log2x)O(log_2 x)O(log2​x)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 300005
#define maxv 15000005
using namespace std;
typedef long long ll;
inline int gcd(int a,int b) {
return b==0?a:gcd(b,a%b);
}
int n;
int a[maxn];
int vis[maxv];
int minprime[maxv];
int cnt[maxv];
int prime[maxv];
int k=0; void sieve(int n) {
for(int i=2; i<=n; i++) {
if(!vis[i]) {
minprime[i]=i;
prime[++k]=i;
}
for(ll j=1; j<=k&&(ll)i*prime[j]<=n; j++) {
minprime[(ll)i*prime[j]]=prime[j];
vis[(ll)i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}
} void div(int x) {
if(!vis[x]||x==1) {
cnt[x]++;
return;
}
while(x>1) {
int t=minprime[x];
cnt[t]++;
while(x%t==0&&x!=1) {
x/=t;
}
}
}
int main() {
scanf("%d",&n);
sieve(15000000);
int g=0;
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
g=gcd(g,a[i]);
}
for(int i=1; i<=n; i++) {
a[i]/=g;
}
for(int i=1; i<=n; i++) {
div(a[i]);
}
int ans=0;
for(int i=2; i<=15000000; i++) {
ians=max(ans,cnt[i]);
}
if(ans==0) printf("-1\n");
else printf("%d\n",n-ans);
}

Codeforces 1047C (线性筛+因数分解)的更多相关文章

  1. Codeforces 385C 线性筛素数

    题意:给定一个数组,求[l,r] 区间,区间里的素数,数组中,能被这个素数整除的个数,再求和. 分析:区间很大,10^9了,找去区间内的素数是不可能的,但是,数组的数很小,而且要能整除区间内的素数,所 ...

  2. Codeforces 822D My pretty girl Noora - 线性筛 - 动态规划

    In Pavlopolis University where Noora studies it was decided to hold beauty contest "Miss Pavlop ...

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

    题目链接:http://codeforces.com/problemset/problem/893/E 题意: 共q组数据(q <= 10^5),每组数据给定x,y(x,y <= 10^6 ...

  4. Codeforces Round #304 (Div. 2)(CF546D) Soldier and Number Game(线性筛)

    题意 给你a,b(1<=b<=a<=5000000)表示a!/b!表示的数,你每次可以对这个数除以x(x>1且x为这个数的因子)使他变成a!/b!/x, 问你最多可以操作多少次 ...

  5. Educational Codeforces Round 37-F.SUM and REPLACE (线段树,线性筛,收敛函数)

    F. SUM and REPLACE time limit per test2 seconds memory limit per test256 megabytes inputstandard inp ...

  6. 【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

    题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i) ...

  7. Educational Codeforces Round 89 (Rated for Div. 2)D. Two Divisors 线性筛质因子

    题目链接:D:Two Divisors 题意: 给你n个数,对于每一个数vi,你需要找出来它的两个因子d1,d2.这两个因子要保证gcd(d1+d2,vi)==1.输出的时候输出两行,第一行输出每一个 ...

  8. bzoj2693--莫比乌斯反演+积性函数线性筛

    推导: 设d=gcd(i,j) 利用莫比乌斯函数的性质 令sum(x,y)=(x*(x+1)/2)*(y*(y+1)/2) 令T=d*t 设f(T)= T可以分块.又由于μ是积性函数,积性函数的约束和 ...

  9. BZOJ 2693: jzptab [莫比乌斯反演 线性筛]

    2693: jzptab Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1194  Solved: 455[Submit][Status][Discu ...

随机推荐

  1. bzoj4819 [Sdoi2017]新生舞会 分数规划+最大费用最大流

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4819 题解 首先上面说, \[ C = \frac{\sum\limits_{i=1}^n a ...

  2. 前端之CSS:CSS选择器

    前端之css样式(选择器)... 一.css概述 CSS是Cascading Style Sheets的简称,中文称为层叠样式表,对html标签的渲染和布局 CSS 规则由两个主要的部分构成:选择器, ...

  3. getopt:命令行选项、参数处理

    在写shell脚本时经常会用到命令行选项.参数处理方式,如: ./test.sh -f config.conf -v --prefix=/home -f 为短选项,它需要一个参数,即config.co ...

  4. IDEA unable to find valid certification path to requested target

    一.报错 Could not transfer artifact org.apache.maven.plugins:maven-install-plugin:pom:2.4 from/to alima ...

  5. twint 安装及使用

    分享这个post是自己方便查,还有中文网界对这个东西介绍太少. 更多的就看github项目twint吧. Installation: git+pip3: git clone https://githu ...

  6. A1065

    判断两数相加是否大于第三数,大于输出true,否则输出false(相等也是false) 1 需要注意数字溢出的问题: 2 先判断溢出,因为在a,b都是负数最小值的情况下,相加直接是正数,在c较小的时候 ...

  7. Day_02-Python的循环结构

    循环结构 应用场景 如果在程序中我们需要重复的执行某条或某些指令,例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向奔跑的指令.当然你可能已经注意 ...

  8. Day_02-Python的分支结构和循环结构

    分支结构 应用场景 迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种结构的代码我们称之为顺序结构.然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家 ...

  9. 多数据源(sql server 2008,二个数据库不ip,)

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  10. Java并行

    序言 Java 有四种并行方式: 1.thread  使用“原汁原味”的裸线程 2.Executor (java 5 以后出现的) 3.Forkjoin 框架 (java 8 出现的) 4.Actor ...