hdu2204 Eddy's爱好

原题:点击打开链接


题意很明确了,即:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。


本题目为容斥原理题目,容斥原理的伪代码如下:

void dfs(int cur , int cmn, int id)
{
    1.计算当前集合|cmn|的个数;
    2.判断id的奇偶,以此判定+或者-, 此处id的判断方法可用(id & 1)位运算来判断;
    3.dfs(cur+1, 重复集合, id + 1); 例子:如果之前计算了p(a),p(b), 即计算p(a)+p(b)-p(a交b);
}
姑且这么解释,希望读者能够看懂。


分析本题:

 如何避免重复计算:

  1.即M的次方为质数。K如果是质数,就不能拆分成为两个数的乘积,减少了部分重复;

  2.还有一种重复是类似与4 ^3 与 8 ^ 2的重复(对于容斥来讲,就是2 ^ (2*3),这种重复就得利用容斥原理清除。

  3.离散数学学得好的可以用代数系统考虑。

 特殊知识:pow(n, 1 / num)可以用于开方。

//============================================================================
// Name        : hdu2204.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
using namespace std;
#define lln long long int

lln prime[20] = {2, 3, 5, 7, 11, 13, 17, 19 ,23, 29, 31, 37, 41, 43, 47, 53, 57,59 ,61};//打表质数,因为2 ^60次方 > 10 ^18
lln ans, tmp, n;


void dfs(int cur, int cmn, int id){
	if(id >= 4)//2 ^ (2 * 5 * 7 = 70 )
		return;
	lln num, i;
	for(i = cur; i < 19; i++){
		num = (lln) pow(n, 1 / (prime[i] * cmn));	//find the same key; pow a ^(1/n) 学到了。
		if(id & 1) 							// id odd, minus or add
			ans += num;
		else
			ans -= num;
		dfs(i+1, cmn * prime[i], id+1);
		//find other
	}
}


void ace(){
	while (cin >> n) {
		ans = 0;
		dfs(0, 1, 1);
		printf("%I64d\n", ans);
	}
}

int main() {
	ace();
	return 0;
}


转载于:https://my.oschina.net/u/1017188/blog/333906

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值