数学 数论

来源:互联网 发布:vm无法识别mac os x 编辑:程序博客网 时间:2024/05/16 15:15

题面去内网找。

这题目。。。。
可以发现,如果数g不良,g*p^k一定也不良。所以搞个数组保留当前有哪几个数是良的。然后对这个数组进行拓展,就是枚举到下一个质数,把当前所有认为是良的数乘上当前质数的多少次方都加进这个数组里(边界就是乘到>m就停,但会炸long long,我傻写了个快乘)。
这样数组就拓展完了,之所以上面我说是”认为良的”数,就是在这里拓展完之后,得把所有不满足的删掉,我用了一个权值树状数组,这个好说。
事实证明(出题人说的)k=233时,p到293这个数组就已经不怎么改变了。其实可以发现,“良”的数越到后面越少,一次拓展最多会让数组×log,而check后又会让数组大幅度减少。效率并不会太差。

#include <cstdio>#include <cstring>#include <algorithm>#define ll long longint n,k,t,tot,cnt,pri_sum,pri[100],mark[300],t1[500505];ll m;struct node{ll id,h;}cun[500505],good[500505];void add(int x,int g){for(int i=x;i;i-=i&(-i))t1[i]+=g;}int q(int x){int s=0;for(int i=x;i<=300000;i+=i&(-i))s+=t1[i];return s;}bool cmp(node x,node y){return x.id<y.id;}bool cheng(ll x,ll y){    ll ans=0;    while(y)    {        if(y&1){ans+=x;if(x<0||ans>m)return 0;}        x+=x;y>>=1;if(x>m)x=-1;    }    return 1;}void init(){    for(int i=2;i<=293;i++)    {        if(!mark[i])pri[++pri_sum]=i;        for(int j=1;j<=pri_sum;j++)        {            if(pri[j]*i>293)break;            mark[pri[j]*i]=1;            if(i%pri[j]==0)break;        }    }    good[++tot]=node{1,1};    for(int i=1;i<=pri_sum;i++)    {        ll f=pri[i];cnt=0;        for(int j=1;j<=tot;j++)        {            node h=good[j];ll sum=2;cun[++cnt]=h;            while(cheng(h.id,f))                h.id*=f,cun[++cnt]=node{h.id,h.h*sum},sum++;        }        tot=0;std::sort(cun+1,cun+cnt+1,cmp);std::memset(t1,0,sizeof(t1));        for(int j=1;j<=cnt;j++)        {            if(q(cun[j].h+1)<=k)good[++tot]=cun[j];            add(cun[j].h,1);        }    }}int main(){    scanf("%d%d%lld",&t,&k,&m);    init();    while(t--)    {        scanf("%lld",&n);        printf("%lld\n",good[n].id);    }}