C#檔案流下載檔案
阿新 • • 發佈:2021-08-16
核心思路:離線演算法,把每次的詢問先記錄下來,按一定的順序排序,然後暴力從上一個區間轉移到下一個區間。
複雜度:
- 當 \(n\) ,\(m\) 同階時,塊長取 \(\sqrt n\) 時,複雜度為 \(O(n \sqrt n)\) ;
- 當 \(m < n\) 時,塊長取 \(\displaystyle \frac{n}{\sqrt{m}}\) 時,複雜度為 \(O(n \sqrt m)\) .
例題 小 Z 的襪子
分析可見 oi-wiki ( /xyx
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; int n,m,k,a[N],ans[N],s[N],ps[N],l,r,blo,sm; ll L[N],R[N]; struct node{ int l,r,sum; void in(int x){scanf("%d%d",&l,&r);sum=x;L[x]=l,R[x]=r;} }qr[N]; bool cmp(node x,node y){return ps[x.r]==ps[y.r]?x.l<y.l:x.r<y.r;} int gx(int x){return s[a[x]]*(s[a[x]]-1)/2;} int main() { scanf("%d%d",&n,&m); blo=n/sqrt(m*2/3);l=1; for(int i=1;i<=n;i++) scanf("%d",&a[i]),ps[i]=(i-1)/blo+1; for(int i=1;i<=m;i++) qr[i].in(i); sort(qr+1,qr+m+1,cmp); for(int i=1;i<=m;i++) { while(l<qr[i].l) sm-=gx(l),s[a[l]]--,sm+=gx(l),l++; while(l>qr[i].l) l--,sm-=gx(l),s[a[l]]++,sm+=gx(l); while(r<qr[i].r) r++,sm-=gx(r),s[a[r]]++,sm+=gx(r); while(r>qr[i].r) sm-=gx(r),s[a[r]]--,sm+=gx(r),r--; ans[qr[i].sum]=sm; } for(int i=1;i<=m;i++) { if(L[i]==R[i]) {puts("0/1");continue;} int gcd=__gcd(ans[i]*1ll,(R[i]-L[i]+1)*1ll*(R[i]-L[i])/2*1ll); printf("%d/%lld\n",ans[i]/gcd,(R[i]-L[i]+1)*1ll*(R[i]-L[i])/2*1ll/gcd); } return 0; }
如果直接求一個序列的答案,發現並不好求。於是考慮求以 \(l\) 為左端點(右端點類似)所造成的貢獻,顯然,當滿足 \(\displaystyle \frac{ s[r]−s[l−1]}{10^{n−r}}\equiv0\pmod{p}\),就找到了一個合法的區間(\(s[i]\) 表示由前 \(i\) 個數和後 \(n−i\) 個 \(0\) 構成的數字)。這樣我們發現,假設我們已知一個區間的答案,可以做到 \(O(1)\) 移動一個單位的端點。而我們要求的,實際上就是區間中等於某個數的位置個數。可以將其離散化之後,用莫隊+桶維護。
code
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+10; inline int read() { int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*w; } #define int long long inline int lread() { int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){if (ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*w; } #undef int int q,ps[N],n,cnt[N],tot,vi[N]; char s[N];ll res[N],ans[N],nw,v[N],t[N],p,x,fc=1; struct node{ int l,r,id; bool operator <(const node &y)const{ return ps[l]==ps[y.l]?r<y.r:ps[l]<ps[y.l]; } }qr[N]; void tepan() { int l,r; for(int i=1;i<=n;i++) { res[i]=res[i-1],cnt[i]=cnt[i-1]; if((s[i]-'0')%p==0) res[i]+=i,cnt[i]++; } while(q--) l=read(),r=read(),printf("%lld\n",res[r]-res[l-1]-(ll)(cnt[r]-cnt[l-1])*(l-1)); exit(0); } void upd(int x) { nw-=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2; if(!vi[x]) cnt[v[x]]++;else cnt[v[x]]--; vi[x]^=1;nw+=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2; } int main() { p=lread();scanf("%s",s+1);q=read(); n=strlen(s+1);int sz=sqrt(n)+1; if(p==2||p==5) tepan(); for(int i=1;i<=n;i++) ps[i]=(i-1)/sz+1; for(int i=n;i;i--) x=(x+(ll)(s[i]-'0')*fc)%p,fc=(ll)fc*10%p,v[i]=t[i]=x; v[++n]=t[n]=0; sort(t+1,t+n+1);tot=unique(t+1,t+n+1)-t-1; for(int i=1;i<=n;i++) v[i]=lower_bound(t+1,t+tot+1,v[i])-t; for(int i=1;i<=q;i++) qr[i].l=read(),qr[i].r=read()+1,qr[i].id=i; sort(qr+1,qr+q+1); int l=1,r=0; for(int i=1;i<=q;i++) { while(r<qr[i].r) upd(++r); while(l>qr[i].l) upd(--l); while(r>qr[i].r) upd(r--); while(l<qr[i].l) upd(l++); ans[qr[i].id]=nw; } for(int i=1;i<=q;i++) printf("%lld\n",ans[i]); return 0; }
\(\texttt{End.}\)