HDU 5297 迭代

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5297

1.看完题有一个大概思路:二分加容斥,容斥的话62以内大约有15个左右的质数,每次容斥如果2^15左肯定超时,但是可以发现很多状态其实不用考虑,比如x^91在long long范围内根本不用考虑。可以先预处理一下,最多需要考虑大约40个状态。这样写了二分交了居然T了。。。

2.一下子搞不清楚能不能用莫比乌斯反演,需要复习一下莫比乌斯反演的使用条件

3.试了下减小二分的范围,T

4.最后查了题解,是迭代的。如果说当前检验的这个数num是第m个合法数字的话,那么第n个合法数字一定>= num + n - m

5.复杂度玄学。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cctype>
#include <cmath>
#include <vector>
#include <sstream>
#include <bitset>
#include <deque>
#include <iomanip>
using namespace std;
#define pr(x) cout << #x << " = " << x << endl;
#define bug cout << "bugbug" << endl;
#define ppr(x, y) printf("(%d, %d)\n", x, y);
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n---------------")

typedef long long ll;
typedef double DBL;
typedef pair<int, int> P;
typedef unsigned int uint;
const int MOD = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e2 + 4;
const int maxm = 1e3 + 4;
const double pi = acos(-1.0);
const double eps = 1e-12;
int a[maxn] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 83, 89}, r;
int tmp[maxn];
ll n, num;
vector<P> v;
vector<int> w;
inline ll compute(int m, ll maxv){
	int num = pow(maxv+0.5, 1.0/m);
	return num - 1;
}
ll fun(ll num, int r){
	ll record = num;
	num--;
//	pr(r);
//	cout << "once " << endl; 
	for (int i = 0; i < v.size(); ++i){
		if (v[i].second > r) break;
//		if (v[i].first == 3){
//			ppr(v[i].first, record);
//			cout << int(compute(v[i].first, record)) * w[i] << endl; 
//			cout << compute(3, 1331) << endl; 
//		} 
		num += compute(v[i].first, record) * w[i];
//		cout << num << endl;
	}
//	system("pause");
	return num;
}
ll binary(ll n, int r){
/*	ll lft = n, rght = n+2e9;
	while(lft < rght){
		ll mid = (lft + rght) / 2;
		if (fun(mid, tmp[r]) >= n) rght = mid;
		else lft = mid + 1;
	}
	*/
	ll lft = n, T;
	while((T = fun(lft, tmp[r])) < n){
		lft += n - T; 
	}
	return lft;
}
int main(){
//必须编译过才能交
	int ik, i, j, k, kase;
//	freopen("input.txt", "r" , stdin);
//	freopen("output.txt", "w", stdout);
	for (i = 1; i < (1 << 18); ++i){
		int base = 1;
		bool flag = true;
		for (j = 0; j < 18; ++j)
			if (i >> j & 1){
				base *= a[j];
				if (base > 62) flag = false;
			}
		if (flag){
			v.push_back({base, i});
			w.push_back((__builtin_popcount(i) & 1) ? -1 : 1);
		}
	}
//	cout << ll(2e18) << endl;
//	cout << pow(1331, 1.0/3) << endl;
//	cout << pow(1331, 1.0/5) << endl;
//	cout << pow(1331, 1.0/7) << endl;
	for (i = 2; i < 63; ++i){
		tmp[i] = lower_bound(a, a+18, i) - a;
		if (a[tmp[i]] != i) tmp[i]--;
		tmp[i]++;
		tmp[i] = (1 << tmp[i]) - 1;
	}
	scanf("%d", &kase);
	while(kase--){
		scanf("%I64d %d", &n, &r);
		printf("%I64d\n", binary(n, r));
//		printf("%d\n", n);
	}
	return 0;
}

/*
100 
1285  10
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值