牛客练习赛10 F-序列查询(莫队+链表)
F-序列查詢
v5zsq題解
假設數字xxx在區間[l,r]種出現y次,那么包含x的子區間個數為2r?l+1?y?(2y?1)2^{r-l+1-y}·(2^y-1)2r?l+1?y?(2y?1),因此對詢問貢獻是x?2r?l+1?y?(2y?1)=x[2r?l+1?2r?l+1?y]x·2^{r-l+1-y}·(2^y-1)=x[2^{r-l+1}-2^{r-l+1-y}]x?2r?l+1?y?(2y?1)=x[2r?l+1?2r?l+1?y]
其中第一部分非常好維護第二部分的貢獻,可以把出現次數相同的數一起維護貢獻 sum[k]維護出現從次數為k的數字總和是多少。用個鏈表加快計算。
注意到一起區間中只有O(n)O( \sqrt n )O(n?)種不同的出現次數因為1+2+...+n=O(n)1+2+...+\sqrt n = O(n)1+2+...+n?=O(n)這是一個自然根號所以我們可以用一個均攤的莫隊來維護區間可能的出現次數,從而維護區間中所有出現次數然后為了O(1)實現快速冪,我們可以每次O(n)O(\sqrt n)O(n?)算出21,22…2nmodp2^1,2^2…2^{\sqrt n} \mod p21,22…2n?modp以及2n,22n…2nnmodp2^{\sqrt n},2^{2\sqrt n}…2^{\sqrt n\sqrt n} \mod p2n?,22n?…2n?n?modp
#include<bits/stdc++.h> #pragma GCC optimize(2) using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } ll qmi(ll a,ll b,ll mod) {ll v=1;while(b){if(b&1) v=v*a%mod;a=a*a%mod;b>>=1;}return v; } const int N=100005; int Bs,b[N],a[N],n,m; struct node {int l,r,p,id;bool operator<(const node&o)const{if(b[l]==b[o.l]){if(b[l]&1) return r<o.r;return r>o.r;}return b[l]<b[o.l];} }q[N]; int num[N],cnt[N]; ll sum[N]; int h,fr[N],ne[N]; int ans[N]; int mod; void insert(int x) {ne[x]=h;fr[h]=x;fr[x]=0;h=x; } void del(int x) {if(h==x) return h=ne[x],void();ne[fr[x]]=ne[x];fr[ne[x]]=fr[x]; } void update(int x,int v) {// 出現個數為num[x]-xif(num[x]){sum[num[x]]-=x;cnt[num[x]]--;if(!cnt[num[x]]) del(num[x]);}num[x]+=v;if(num[x]){sum[num[x]]+=x;cnt[num[x]]++;if(cnt[num[x]]==1) insert(num[x]);} } int add(int a,int b) {a+=b;if(a>=mod) a-=mod;return a; } int mul(int a,int b) {ll z=1ll*a*b;return z-z/mod*mod; } int f[1005],g[1005]; void init(int n) {f[0]=1;for(int i=1;i<=Bs;i++) f[i]=add(f[i-1],f[i-1]);g[0]=1;for(int i=1;i<=n/Bs;i++) g[i]=mul(g[i-1],f[Bs]); } int Pow(int n) {return mul(g[n/Bs],f[n%Bs]); } int query(int l,int r,int p) {mod=p;int len=r-l+1;init(n); int ans=0;for(int i=h;i;i=ne[i]) ans=add(ans,mul(sum[i]%p,add(Pow(len),p-Pow(len-i))));return ans; } int main() {n=rd(),m=rd();for(int i=1;i<=n;i++) a[i]=rd();Bs=sqrt(n)+1;for(int i=1;i<=n;i++) b[i]=(i-1)/Bs+1;for(int i=1;i<=m;i++) q[i].l=rd(),q[i].r=rd(),q[i].p=rd(),q[i].id=i;sort(q+1,q+1+m);int l=1,r=0;for(int i=1;i<=m;i++){while(r<q[i].r) update(a[++r],1);while(r>q[i].r) update(a[r--],-1);while(l<q[i].l) update(a[l++],-1);while(l>q[i].l) update(a[--l],1);ans[q[i].id]=query(q[i].l,q[i].r,q[i].p);}for(int i=1;i<=m;i++) printf("%d\n",ans[i]);} 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的牛客练习赛10 F-序列查询(莫队+链表)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 霁字怎么读 霁读音
- 下一篇: P4062 [Code+#1]Yazid