第六十六题 UVA10375 选择与除法 Choose and divide

116 篇文章 1 订阅
75 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
输入输出样例
输入 #1复制
10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
输出 #1复制
0.12587
505606.46055
1.28223
0.48996
2.00000
3.99960

// 唯一分解定理   任意一个数都可以写成好多个素数想乘的形式
#include<iostream> 
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>

using namespace std;
const int Maxn = 10000;
int e[Maxn + 1];
vector<int> primes;
inline bool is_prime(int n) {
	int m = sqrt(n + 0.5); 
	for(int i=2; i<=m; i++)
		if(n % i == 0) return false;// 暴力检验素数 
	return true;
}

inline void Add(int n,int d) {
	for(int i=0; i<primes.size(); i++){
		while(n % primes[i] == 0) {
			n /= primes[i];
			e[i] += d;
		}
		if(n == 1) break;
	}
	return ;
} 

inline void add(int n,int d) {
	for(int i=1; i<=n; i++)
		Add(i,d);
}
bool vis[Maxn + 1]; 
int main(int argc,char* argv[])  {
	memset(vis,0,sizeof(vis));
	vis[0] = vis[1] = 1;// 1 代表不是素数 
	for(int i=2; i<=Maxn; i++) {// 欧拉筛法 就当复习一下了 
		if(!vis[i]) primes.push_back(i);
		for(int j=0; j<primes.size()&&i*primes[j]<=Maxn; j++) {
			vis[i * primes[j]] = 1;
			if(i % primes[j] == 0) break;
		}
	}
	//for(int i=0; i<primes.size(); i++) printf("%d ",primes[i]);
	int p,q,r,s;
	while(scanf("%d%d%d%d",&p,&q,&r,&s) == 4) {
		memset(e,0,sizeof(e));
		add(p,1);
		add(p-q,-1);
		add(q,-1);
		add(r,-1);
		add(s,1);
		add(r-s,1);
		double Ans = 1;
		for(int i=0; i<primes.size(); i++)
			if(e[i]) Ans *= pow(primes[i],e[i]);
		printf("%.5lf\n",Ans);
	}
	return 0;
}
// 埃氏筛法
int visit[maxn];  
void Prime(){
    mem(visit,0);           //初始化都是素数
    visit[0] = visit[1] = 1;  //0 和 1不是素数
    for (int i = 2; i <= maxn; i++) {
        if (!visit[i]) {         //如果i是素数,让i的所有倍数都不是素数
            for (int j = i*i; j <= maxn; j += i) { 
                visit[j] = 1;
            }
        }
    }
  • 埃氏筛法的缺陷 :对于一个合数,有可能被筛多次。例如 30 = 2 * 15 = 3 * 10 = 5*6……那么如何确保每个合数只被筛选一次呢?我们只要用它的最小质因子来筛选即可,这便是欧拉筛法。
// 欧拉筛法
for(int i=2; i<=Maxn; i++) {// 欧拉筛法 就当复习一下了 
		if(!vis[i]) primes.push_back(i);
		for(int j=0; j<primes.size()&&i*primes[j]<=Maxn; j++) {
			vis[i * primes[j]] = 1;
			if(i % primes[j] == 0) break;
		}
	}
  • 关于 i%prime[j] == 0 就break的解释 :(其实这玩意我这个寒假回来看,第一遍自己啥也没看懂,还是去网上找的,看了老半天勉强算是看懂了吧)当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
    举个例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值