例题:
给出上限n,求第k个小于等于n的数满足小于该数的约数个数比它大的数不超过x个.
n<=1e18 , x<= 233
根据ZJOI反质数的经验,我们可以利用很少的质数来更新解决此题.
很容易知道以下性质:
我们对于一个质数p考虑x小于p质数相乘所得的集合G,对于G中的所有元素如果现在没有被我们选中那么显然
x * p ^ y(y>=0) 也一定不会被我们选中.所以我们利用上一个筛选序列乘上若干个当前质数加入候选序列,从小到大排序,维护前k大的因子个数每次加入时比较更新一下即可.
由于大质数的不优性我们可以利用这种乱搞方法高正确率的做出结果.
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//math problem when requires about sth about the numbers of divisors then you can limit the number of primes to get AC.
//yusing the stagety that slowly extends the num of the primes and diedai.
//We'll first use the larger primes' bad xingzhi to decrease the range .
//We'll sort the possible choices , so that we'll just care about the last one's divisor number.And then we update it , and reupdate the queue.
//go to have a zongjie
typedef long long LL;
const LL N = 1000005;
const LL M = 234;
#define Pair pair<LL,int>
bool isp[305];
LL n , m , t;
int mx[N] , cnt , tot , pr[305] , all;
Pair ans[N] , Nowqueue[N];
void prework(void) {
memset(isp , 1,sizeof(isp)); isp[1] = 0;
for(LL i = 1;i <= 300;i ++) {
if(isp[i]) pr[++ cnt] = i;
for(LL j = 1;j <= cnt && pr[j] * i <= 300;j ++) {
isp[pr[j] * i] = 0;
if(pr[j] % i == 0) break;
}
}
}
bool pd(LL x , LL y) {
LL it = 0;
while(y) {
if(y & 1) it += x;
y >>= 1;
if(it > n || x > n) return 0;
x *= 2;
}
return 1;
}
void update(int x) {
int p = m;
while(p && x >= mx[p - 1]) p --;
for(LL i = m;i > p;i --) mx[i] = mx[i - 1];
mx[p] = x;
}
void dothat(void) {
prework();
ans[++ tot] = make_pair(1 , 1);
for(int i = 1;i <= cnt;i ++) {
all = 0; LL wh = pr[i];
for(int j = 1;j <= tot;j ++) {
Nowqueue[++ all] = ans[j];
LL now = wh , w = 1;
while(pd(Nowqueue[all].first , wh)) {
all ++;
Nowqueue[all] = make_pair(Nowqueue[all - 1].first * now , ans[j].second * (w + 1));
w ++; if(now > n) break;
}
}
sort(Nowqueue + 1 , Nowqueue + all + 1);
memset(mx , 0 ,sizeof(mx));
tot = 0;
for(LL j = 1;j <= all;j ++) {
if(Nowqueue[j].second >= mx[m]) {
update(Nowqueue[j].second); ans[++ tot] = Nowqueue[j];
}
}
}
}
int main(void) {
scanf("%lld%lld%lld",&t,&m,&n);
dothat();
int x;
for(int i = 1;i <= t;i ++) {
scanf("%d",&x);
if(x > tot) puts("-1");
else printf("%lld\n",ans[x].first);
}
}