P1069 [NOIP2009 普及组] 细胞分裂 T3
#include <bits/stdc++.h>
using namespace std;
int n, s[10010], m1, m2, cnt, prim[3246], target[3246];
double curans, ans=1e9;
//打表计算 30000 以内的质数, 并存在数组prim中
inline void ini()
{
for(int i=2; i<30000; ++i){
bool flag=true;
for(int j=2; j<=sqrt(i); ++j){
if(i%j==0){
flag=false;
break;
}
}
if(flag){
cnt++;
prim[cnt]=i;
}
}
}
int main()
{
ini();
cin >> n >> m1 >> m2;
for(int i=1; i<=n; ++i){
scanf("%d", &s[i]);
}
//如果m1等于1, 则无法质因数分解, 不需要任何分裂, 可以直接将细胞放进去即可
//注意这一段特判不能放在对m1质因数分解后面, 因为m1质因数分解以后肯定为1
if(m1==1){
puts("0");
return 0;
}
//对m1进行质因数分解
for(int i=1; i<=cnt && m1>1; ++i){
while(m1%prim[i]==0){
target[i]+=m2; //target[i] 记录m1的m2次方里面总共有多少个质因数 prim[i]
m1/=prim[i];
}
}
for(int i=1; i<=n; ++i){ //枚举每一种细胞
bool flag=true;
for(int j=1; j<=cnt; ++j){ //枚举所有的质因数
//s[i]无法整除m1中的质因数prim[j], 第i种细胞始终无法实现目标
if(target[j]!=0 && s[i]%prim[j]!=0){
flag=false;
break;
}
}
if(flag==true){
//对s[i]进行质因数分解
curans=0;
//枚举m1的m2次方中所有的质因数
for(int j=1; j<=cnt && s[i]>1; ++j){
double asd=0; //记录s[i]中有几个质因数prim[j]
//只分解有用的质因数
while(target[j] && s[i]%prim[j]==0){
asd++;
s[i]/=prim[j];
}
curans=max(curans, ceil(target[j]/asd));
}
if(curans!=0){
ans=min(ans, curans);
}
}
}
if(ans==1e9){
printf("-1");
}
else{
printf("%.0lf", ans);
}
return 0;
}
P1414 又是毕业季II 因数分解一道题目,降复杂度的思路妙
#include <bits/stdc++.h>
using namespace std;
int n, a[10010], mx, cnt[1000010];
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; ++i){
scanf("%d", &a[i]);
mx=max(mx, a[i]);
}
//统计每个因数出现的次数, 传统的根号优化
for(int i=1; i<=n; ++i){
for(int j=1; j<=sqrt(a[i]); ++j){ //这里粗心把sqrt(a[i])写成sqrt(i)了
if(a[i]%j==0){
cnt[j]++;
if(j*j!=a[i]){
cnt[a[i]/j]++;
}
}
}
}
//因为数字越大, 出现为因子的次数越少, 所以cnt数组是倒序的
//这么写能够降低复杂度, 复杂度降到了O(mx)
for(int i=1; i<=n; ++i){
//如果大的mx作为因数出现的次数不够i次, 那更不可能够i+1次
while(cnt[mx]<i){
mx--;
}
printf("%d\n", mx);
}
return 0;
}
P1072 [NOIP2009 提高组] Hankson 的趣味题 枚举,gcd lcm推式子后能降低枚举的复杂度
#include <bits/stdc++.h>
using namespace std;
int n, a0, a1, b0, b1, ans, k1, k2, p1, p2, x0;
int main()
{
scanf("%d", &n);
while(n--){
scanf("%d %d %d %d", &a0, &a1, &b0, &b1);
ans=0;
//x和a0的最大公约数为a1, x=k1*a1, a0=k2*a1, k1 k2互质
k2=a0/a1;
//x和b0的最小公倍数为b1, b1=p1*x, b1=p2*b0, p1 p2互质
p2=b1/b0;
//枚举x验证是否满足两个互质条件
//注意:虽然x是大于等于a1的, 但是枚举时得从1开始, 不然就漏掉了b1那些大因子
for(int x=1; x<=sqrt(b1); ++x){
if(b1%x==0){
x0=b1/x;
if(x%a1==0){
k1=x/a1;
p1=b1/x;
if(__gcd(k1, k2)==1 && __gcd(p1, p2)==1){
ans++;
}
}
if(x!=x0 && x0%a1==0){
k1=x0/a1;
p1=b1/x0;
if(__gcd(k1, k2)==1 && __gcd(p1, p2)==1){
ans++;
}
}
}
}
printf("%d\n", ans);
}
return 0;
}