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('\n'); 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\n"); continue;} R pos=upper_bound(num[k].begin(),num[k].end(),n)-num[k].begin()-1; printf("%d\n",sum[k][pos]); } //while(1); }
2019.05.17