题目大意:给出一个长度为n的数列a。
对于一个询问lj和rj。将a[lj]到a[rj]从小到大排序后并去重。设得到的新数列为b,长度为k,求F1*b1+F2*b2+F3*b3+...+Fk*bk。当中F为斐波那契数列。F1=F2=1。对每一个询问输出答案模m。
区间查询离线 用莫队算法
开棵权值线段树,然后用斐波那契的性质update
F(n+m)=F(n+1)*F(m)+F(n)*F(m-1);
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } int P; int sx[30005]; int icnt; inline int Bin(int x){ return lower_bound(sx+1,sx+icnt+1,x)-sx; } struct SEGTREE{ struct node{ int k; int fk,fk_1; int a1,a2; friend node operator + (node &A,node &B){ if (!A.k) return B; if (!B.k) return A; node ret; ret.k=A.k+B.k; (ret.fk=(A.fk+A.fk_1)*B.fk+A.fk*B.fk_1)%=P; (ret.fk_1=A.fk*B.fk+A.fk_1*B.fk_1)%=P; ret.a1=A.a1; (ret.a1+=A.fk*B.a2+A.fk_1*B.a1)%=P; ret.a2=A.a2; (ret.a2+=(A.fk+A.fk_1)*B.a2+A.fk*B.a1)%=P; return ret; } }; node T[120005]; int cnt[120005]; int M,TH; inline void Build(int n){ for (M=1,TH=0;M<n+2;M<<=1,TH++); } inline int Query(){ return T[1].a1; } inline void Change(int s,int r){ s+=M; if (r==1) { cnt[s]++; if (cnt[s]==1) { T[s].k=1; T[s].fk=1; T[s].fk_1=0; (T[s].a1=sx[s-M])%=P; (T[s].a2=sx[s-M])%=P; while (s>>=1) T[s]=T[s<<1]+T[s<<1|1]; } } else if (r==-1) { cnt[s]--; if (cnt[s]==0) { T[s].k=0; T[s].fk=0; T[s].fk_1=0; T[s].a1=0; T[s].a2=0; while (s>>=1) T[s]=T[s<<1]+T[s<<1|1]; } } } }SEG; int n,Q,B; int a[30005],ans[30005]; struct event{ int x,y,lpos; int idx; bool operator < (const event &B) const{ return lpos==B.lpos?y<B.y:lpos<B.lpos; } }eve[30005]; inline void Mos() { int l=1,r=0; for (int i=1;i<=Q;i++) { while (r<eve[i].y) SEG.Change(Bin(a[++r]),1); while (r>eve[i].y) SEG.Change(Bin(a[r--]),-1); while (l<eve[i].x) SEG.Change(Bin(a[l++]),-1); while (l>eve[i].x) SEG.Change(Bin(a[--l]),1); ans[eve[i].idx]=SEG.Query(); } } int main() { freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(P); B=sqrt(n); for (int i=1;i<=n;i++) read(a[i]),sx[++icnt]=a[i]; sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1; SEG.Build(icnt); read(Q); for (int i=1;i<=Q;i++) { read(eve[i].x); read(eve[i].y); eve[i].lpos=(eve[i].x-1)/B+1; eve[i].idx=i; } sort(eve+1,eve+Q+1); Mos(); for (int i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0; }
然而出题人太奇妙,这样的做法常数极大,还是暴力短小精悍
#include<bits/stdc++.h> using namespace std; const int maxn = 3e4+5; pair<int,int> a[maxn]; int ans[maxn],step[maxn],f[maxn],l[maxn],r[maxn],last[maxn]; int main() { freopen("t.in","r",stdin); freopen("t1.out","w",stdout); int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i].first),a[i].second=i; sort(a+1,a+1+n); f[0]=1,f[1]=1; for(int i=2;i<=n;i++) f[i]=(f[i-1]+f[i-2])%m; int q;scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%d%d",&l[i],&r[i]); last[i]=-1; } for(int i=1;i<=n;i++) { int d = a[i].first % m; for(int j=1;j<=q;j++) { if(a[i].second<l[j]||a[i].second>r[j])continue; if(a[i].first==last[j])continue; ans[j]=(ans[j]+f[step[j]++]*d)%m; last[j]=a[i].first; } } for(int i=1;i<=q;i++) printf("%d\n",ans[i]); }
时间: 2024-10-13 16:59:27