[CSP-S模擬測試]:數論(數學)

題目傳送門(內部題11)


輸入格式

第一行,三個整數$T,K,M$,分別表明數據組數、良好標準和整數範圍。
接下來$T$行,每行一個整數$n_i$,表明一個詢問。
html


輸出格式

輸出$T$行,在第$i$行對於詢問$i$輸出一個整數,表明第$n_i$個良好的整數。
保證答案必定不超過給定的$M$。
c++


樣例

樣例輸入1:算法

1 0 23333
10
spa

樣例輸出1:htm

20blog

樣例輸入2:排序

3 5 998244353
28
165
233
get

樣例輸出2:it

42
9360
63360
class


數據範圍與提示

樣例1解釋:

前$10$個優秀的整數是$1,2,3,4,6,8,10,12,18,20$。

數據範圍:

對於全部數據,$1\leqslant T\leqslant 20,0\leqslant K\leqslant 233,1\leqslant n_i\leqslant M\leqslant {10}^{18}。


題解

對於一個質數$p$,咱們考慮全部僅包含小於$p$的質因子的正整數集$G$。不難發現:
  若$x\in G$,且在$G$中已經有超過$K$個小於$x$的整數約數個數多於$x$,即$x$必定不是良好的,則$xp^c(c\geqslant 0)$也必定不多是良好的。
這樣咱們就能夠獲得一個初步的想法。開始咱們認爲僅有$1$是良好的,枚舉質因子$p$,對於每個原來認爲是良好的數$x$,將$xp^c(c\geqslant 0)$加入候選列表,接着將候選列表排序,除去已經能夠肯定不是良好的數,進入下一輪迭代。容易證實,在這個算法中,篩去一個不是良好的數$x$,是不會在後續過程當中令一個本來不是良好的數,變成一個良好的數的,故篩去良好的數的過程是合法的剪枝。
然而枚舉的質因子的範圍有多大呢?聯想$K=0$這一經典問題,咱們知道對於${10}^{18}$的範圍,考慮前$20$個質因子都綽綽有餘了,由於將更大的質因子加入是很是不優的。在$K$更大的時候,咱們採用「迭代至穩定」的思想,每一輪迭代後檢查答案是否變化,若是在較長一段迭代後答案無任何變化,咱們就認爲質因子$p$的上界已經達到。通過實踐,在$K=233$時,$p$的最大值取到$293$便可。
咱們考慮如何在一輪迭代中除去肯定不是良好的數。考慮維護前$K+1$大值,從小到大枚舉候選列表中的數$x$,若$x$小於第$K+1$大值,咱們就把這個數除去。不然更新前$K+1$大值。根據上述描述能夠大體估算複雜度。設$K=233$時,${10}^{18}$內良好的數的數量爲$N$,通過實踐,能夠知道$N$約爲$50,000$。每次擴展最多把一個數擴展成$\log M$個數,在剪枝完畢後,列表大小又迴歸到$N$如下。

時間複雜度:$\Theta((N\times K\times \max(p)\log M)$。

指望得分:$100$分。

實際得分:$100$分。


代碼時刻

#include<bits/stdc++.h>
using namespace std;
int T,K;
long long M;
int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293};
int cnt,num,size;
pair<int,long long> heap[200000],que[200000],flag[200000];
bool cmp(pair<int,long long> x,pair<int,long long> y){return x.second==y.second?x.first<y.first:x.second<y.second;}
void up(int x)
{
	while(x>1)
		if(heap[x]<heap[x>>1])
		{
			swap(heap[x],heap[x>>1]);
			x>>=1;
		}
		else break;
}
void insert(pair<int,long long> x){heap[++size]=x;up(size);}
void down(int x)
{
	int s=x<<1;
	while(s<=size)
	{
		if(s<size&&heap[s]>heap[s|1])s|=1;
		if(heap[s]<heap[x])
		{
			swap(heap[s],heap[x]);
			x=s;
			s=x<<1;
		}
		else break;
	}
}
void change(pair<int,long long> x){heap[1]=x;down(1);}
int main()
{
	scanf("%d%d%lld",&T,&K,&M);
	que[++cnt]=make_pair(1,1);
	for(int i=0;i<62;i++)
	{
		num=0;
		long long lft=0,rht=M/prime[i],k=0;
		while(lft<=rht)
		{
			lft=max(lft*prime[i],1LL);
			k++;
			for(int j=1;j<=cnt&&lft*que[j].second<=M;j++)
				flag[++num]=make_pair(que[j].first*k,lft*que[j].second);
		}
		sort(flag+1,flag+num+1,cmp);
		int lst=cnt;
		cnt=size=0;
		for(int j=1;j<=min(K+1,num);j++)
		{
			insert(flag[j]);
			que[++cnt]=flag[j];
		}
		for(int j=min(K+1,num)+1;j<=num;j++)
			if(flag[j].first>=heap[1].first)
			{
				change(flag[j]);
				que[++cnt]=flag[j];
			}
		if(lst==cnt)break;
	}
	while(T--)
	{
		int x;
		scanf("%d",&x);
		printf("%lld\n",que[x].second);
	}
	return 0;
}

rp++

相關文章
相關標籤/搜索