zoukankan      html  css  js  c++  java
  • Luogu P4901 排队 fib数列+树状数组+倍增

    这题让我升华。。还好只重构了一遍


    首先我们发现:$n$较小时,整个队伍的形态 跟 $n$ 比较大时的局部是一样的

    所以我们预处理出这个队伍的形态,和每一行每个位置的质因子个数的前缀和,$O(nlogn)$,然后每次回答$log(n)$

    方法:

    1.线性筛,筛出每个数值因子的个数;

    2.然后用一个树状数组,维护整个队列中的还存在的数的数量;相当于统计一个数组(设其为$a$)的前缀和,这个数组以自己为下标,存储这个数还存不存在,即$a[x]=1表示x存在,a[x]=0表示x不存在$;刚开始$a$中都为$1$,当某个数$x$被删除时,单点修改$a[x]=0$.

    3.查询排名:这里要用到倍增的思路。因为当树状数组的下标$pos==2^k$时,它维护的是$[1,2^k]$的前缀和,所以根据树状数组的思想,可以倍增查找;

    4.因为每次查询后都会删一个数,所以查询的实际位置是$fib[i]-已经删去的数的个数,即fib[i]-i+1$

    5.最后对于每一个询问,在预处理出的 队伍形态 的数组的第$k$行中,查找编号小于但最接近$n$的那个数数的位置,对应到前缀和数组中的位置就是答案。

    但是自己还有个疑问:为何空间开一半就够了。。。自己一直MLE,看了题解才开了一半qwq

    PS:bitset比bool 快一些

    代码:

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<bitset>
    #define R register int
    const int N=5000000,K=10000;
    using namespace std;
    inline int g() {
        R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
        do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    }
    int c[N+1],fib[38];
    inline int lbt(int x) {return x&-x;}
    inline void add(int pos,int vl) {for(;pos<=N;pos+=lbt(pos)) c[pos]+=vl;}
    int pri[N/11],tot;
    short cnt[N+1];
    bitset<N+1> vis;
    inline void PRI() {
        for(R i=2;i<=N;++i) {
            if(!vis[i]) pri[++tot]=i,cnt[i]=1;
            for(R j=1;j<=tot&&i*pri[j]<=N;++j) {
                vis[i*pri[j]]=true,cnt[i*pri[j]]=cnt[i]+1;
                if(i%pri[j]==0) break;
            }
        } 
    }
    vector<int> sum[K+1],num[K+1];
    inline int query(int rk) {
        R pos=0,tot=0; for(R t=22;t>=0;--t) 
            if(tot+c[pos+(1<<t)]<rk) pos+=(1<<t),tot+=c[pos];
        return pos+1;
    }
    inline void PRE() { PRI(); fib[1]=1,fib[2]=2;
        for(R i=3;i<=37;++i) fib[i]=fib[i-1]+fib[i-2];
        for(R i=1;i<=N;++i) add(i,1); R tot=N;
        for(R i=1;i<=K;++i) for(R j=1;fib[j]-j+1<=tot;++j) {
            R pos=query(fib[j]-j+1); add(pos,-1),--tot; //cout<<pos<<" "<<cnt[pos]; putchar('
    ');
            if(j>=2) sum[i].push_back(sum[i][j-2]+cnt[pos]);
            else sum[i].push_back(cnt[pos]);
            num[i].push_back(pos);
        }
    }
    signed main() { PRE(); R t=g();
        for(R i=1;i<=t;++i) {
            R n=g(),k=g(); if(num[k][0]>n) {printf("-1
    "); continue;}
            R pos=upper_bound(num[k].begin(),num[k].end(),n)-num[k].begin()-1;
            printf("%d
    ",sum[k][pos]);
        } //while(1);
    }

    2019.05.17

  • 相关阅读:
    oracle中Blob和Clob类型的区别
    为什么要分库分表
    Enable file editing in Visual Studio's debug mode
    SQL Server Dead Lock Log
    Debug .NET Framework Source
    SQL Server text field里面有换行符的时候copy到excel数据会散乱
    诊断和修复Web测试记录器(Web Test Recorder)问题
    Can't load Microsoft.ReportViewer.ProcessingObjectModel.dll
    'telnet' is not recognized as an internal or external command
    Linq to XML
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10879066.html
Copyright © 2011-2022 走看看