• 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

  • 相关阅读:
    深度学习网络调试技巧
    深度学习网络调参技巧
    用深度学习解决大规模文本分类问题
    [译] 理解 LSTM 网络
    一文学会用 Tensorflow 搭建神经网络
    tensorflow实现基于LSTM的文本分类方法
    用keras实现lstm 利用Keras下的LSTM进行情感分析
    TensorFlow练习7: 基于RNN生成古诗词
    【深度学习】文本生成
    Leetcode--easy系列5
  • 原文地址:https://www.cnblogs.com/Jackpei/p/10879066.html
Copyright © 2020-2023  润新知