zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:数论(数学)

    题目传送门(内部题11)


    输入格式

    第一行,三个整数$T,K,M$,分别代表数据组数、良好标准和整数范围。
    接下来$T$行,每行一个整数$n_i$,代表一个询问。


    输出格式

    输出$T$行,在第$i$行对于询问$i$输出一个整数,代表第$n_i$个良好的整数。
    保证答案一定不超过给定的$M$。


    样例

    样例输入1:

    1 0 23333
    10

    样例输出1:

    20

    样例输入2:

    3 5 998244353
    28
    165
    233

    样例输出2:

    42
    9360
    63360


    数据范围与提示

    样例1解释:

    前$10$个优秀的整数是$1,2,3,4,6,8,10,12,18,20$。

    数据范围:

    对于所有数据,$1leqslant Tleqslant 20,0leqslant Kleqslant 233,1leqslant n_ileqslant Mleqslant {10}^{18}。


    题解

    对于一个质数$p$,我们考虑所有仅包含小于$p$的质因子的正整数集$G$。不难发现:
      若$xin G$,且在$G$中已经有超过$K$个小于$x$的整数约数个数多于$x$,即$x$一定不是良好的,则$xp^c(cgeqslant 0)$也一定不可能是良好的。
    这样我们就可以得到一个初步的想法。开始我们认为仅有$1$是良好的,枚举质因子$p$,对于每一个原来认为是良好的数$x$,将$xp^c(cgeqslant 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 imes K imes 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
    ",que[x].second);
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    把git项目放到个人服务器上
    关于fcitx无法切换输入法的问题解决
    博客变迁通知
    (欧拉回路 并查集 别犯傻逼的错了) 7:欧拉回路 OpenJudge 数据结构与算法MOOC / 第七章 图 练习题(Excercise for chapter7 graphs)
    (并查集) HDU 1856 More is better
    (并查集 不太会) HDU 1272 小希的迷宫
    (并查集 注意别再犯傻逼的错了) HDU 1213 How Many Tables
    (最小生成树 Kruskal算法) 51nod 1212 无向图最小生成树
    (并查集) HDU 1232 畅通工程
    (最小生成树 Prim) HDU 1233 还是畅通工程
  • 原文地址:https://www.cnblogs.com/wzc521/p/11367276.html
Copyright © 2011-2022 走看看