T1 [国家集训队]小Z的袜子(普通莫队模板)
-
设在询问区间中,不同颜色袜子的数量为 a , b , c , . . , z a,b,c,..,z a,b,c,..,z,和为n。
P = a ∗ ( a − 1 ) + b ∗ ( b − 1 ) + c ∗ ( c − 1 ) + . . . + z ∗ ( z − 1 ) n ∗ ( n − 1 ) = a 2 + b 2 + c 2 + . . . + z 2 − a − b − c − . . . − z n ∗ ( n − 1 ) = a 2 + b 2 + c 2 + . . . + z 2 − n n ∗ ( n − 1 ) P=\frac{a*(a-1)+b*(b-1)+c*(c-1)+...+z*(z-1)}{n*(n-1)} \\ =\frac{a^2+b^2+c^2+...+z^2-a-b-c-...-z}{n*(n-1)} \\ =\frac{a^2+b^2+c^2+...+z^2-n}{n*(n-1)} P=n∗(n−1)a∗(a−1)+b∗(b−1)+c∗(c−1)+...+z∗(z−1)=n∗(n−1)a2+b2+c2+...+z2−a−b−c−...−z=n∗(n−1)a2+b2+c2+...+z2−n -
将询问排序。
首先对序列分块(注意不是对询问分块),块大小为 n \sqrt{n} n。
对于询问,若L在不同块中,按R从小到大排序;否则按L从小到大排序。 -
设两个指针L,R。
对于当前询问 Q i Q_i Qi,L和R最初指在 Q i − 1 . l Q_{i-1}.l Qi−1.l和 Q i − 1 . r Q_{i-1}.r Qi−1.r上。
若L< Q i . l Q_i.l Qi.l, a n s + = 1 − 2 ∗ c n t [ a [ L ] ] , c n t [ a [ L ] ] − − ans+=1-2*cnt[a[L]],cnt[a[L]]-- ans+=1−2∗cnt[a[L]],cnt[a[L]]−−。如果仍小于,则继续这个过程。
(其中cnt[i]表示颜色i的数量)
其他情况同理。
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 50000
#define ll long long
#define read(x) scanf("%d",&x)
struct Pair{
int x,y;
int Id;
bool insq;
Pair(){}
};
int cc;
bool cmp(const Pair& x,const Pair& y) {
return x.x/cc==y.x/cc?x.y<y.y:x.x<y.x;
}
int n,m;
int a[maxn+5];
Pair q[maxn+5];
int ans[maxn+5];
int cnt[maxn+5];
int pans[maxn+5];
ll pans2[maxn+5];
int gcd(ll x,ll y) {
if(y==0) return x;
return gcd(y,x%y);
}
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++) read(q[i].x),read(q[i].y),q[i].Id=i;
cc=sqrt(n);
sort(q+1,q+m+1,cmp);
int L=1,R=0;
for(int i=1;i<=m;i++) {
ans[i]=ans[i-1];
while(L<q[i].x) ans[i]+=1-2*cnt[a[L]],cnt[a[L]]--,L++;
while(L>q[i].x) L--,ans[i]+=2*cnt[a[L]]+1,cnt[a[L]]++;
while(R>q[i].y) ans[i]+=1-2*cnt[a[R]],cnt[a[R]]--,R--;
while(R<q[i].y) R++,ans[i]+=2*cnt[a[R]]+1,cnt[a[R]]++;
if(L==R) {pans[q[i].Id]=0,pans2[q[i].Id]=1;continue;}
pans[q[i].Id]=ans[i]-(q[i].y-q[i].x+1),pans2[q[i].Id]=(q[i].y-q[i].x+1)*((ll)q[i].y-q[i].x);
}
for(int i=1;i<=m;i++) {
ll x=pans[i],y=pans2[i];
ll g=gcd(x,y);
printf("%lld/%lld\n",x/g,y/g);
}
return 0;
}
T2 小清新人渣的本愿
-
bitset<>
可看做一个01串,可用下标访问,可以实现左移右移以及其他位运算。 -
减法:
用bitset S1的每一位表示是否有数为该值。
若S1&S1>>x==true,则存在两个数差为x。 -
加法:
基本同减法,另开一个bitset S2 ,每一位表示是否有数表示 maxn-i。
若S1&S2>>maxn-x,则存在两个数和为x。 -
乘法:
暴力枚举因数。 -
莫队处理多组数据
代码:
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define maxn 100000
struct Q{
int opr,l,r,x;
int Id,insq;
Q(){}
};
int n,m;
int a[maxn+5];
Q q[maxn+5];
int cc;
bool cmp(const Q& x,const Q& y) {return x.l/cc==y.l/cc?x.r<y.r:x.l<y.l;}
bitset<maxn+5> S1,S2;
int cnt[maxn+5],ans[maxn+5];
void Add(int x) {cnt[x]++;if(cnt[x]==1) S1[x]=S2[maxn-x]=1;}
void Del(int x) {cnt[x]--;if(cnt[x]==0) S1[x]=S2[maxn-x]=0;}
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++) read(q[i].opr),read(q[i].l),read(q[i].r),read(q[i].x),q[i].Id=i;
cc=sqrt(n);
sort(q+1,q+1+m,cmp);
int L=1,R=0;
for(int i=1;i<=m;i++) {
while(L>q[i].l) Add(a[--L]);
while(L<q[i].l) Del(a[L++]);
while(R>q[i].r) Del(a[R--]);
while(R<q[i].r) Add(a[++R]);
if(q[i].opr==1) ans[q[i].Id]=(S1&S1>>q[i].x).any();
else if(q[i].opr==2) ans[q[i].Id]=(S1&S2>>(maxn-q[i].x)).any();
else {
for(int j=1;j*j<=q[i].x;j++) {
if(q[i].x%j==0&&S1[j]&S1[q[i].x/j]) {ans[q[i].Id]=true;break;}
}
}
}
for(int i=1;i<=m;i++) {
if(ans[i]) printf("hana\n");
else printf("bi\n");
}
return 0;
}
T3 [国家集训队]数颜色 / 维护队列(带修莫队)
-
增加一维时间轴T。
排序时,先分块,按L排;L在同一块,按R排;R也在同一块,按T排。 -
询问时增加T指针。
-
其他部分同普通莫队。
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000
#define read(x) scanf("%d",&x)
struct Q{
int l,r;
int Id,lstc,insq;
Q(){}
};
struct C{
int x,v;
C(){}
};
int n,m;
int a[maxn+5];
Q q[maxn+5];
C c[maxn+5];
int mq,mc;
int cc;
bool cmp(const Q& x,const Q& y) {
if(x.l/cc!=y.l/cc) return x.l<y.l;
if(x.r/cc!=y.r/cc) return x.r<y.r;
return x.lstc<y.lstc;
}
int cnt[maxn+5],s=0;
int ans[maxn+5];
void Add(int x) {if(!cnt[x]++) s++;}
void Del(int x) {if(!--cnt[x]) s--;}
void Work(int i,int t) {
if(c[t].x>=q[i].l&&c[t].x<=q[i].r) {
if(!--cnt[a[c[t].x]]) s--;
if(!cnt[c[t].v]++) s++;
}
swap(c[t].v,a[c[t].x]);
}
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=m;i++) {
char opr;
while(scanf("%c",&opr)&&!isalpha(opr));
if(opr=='Q') {
read(q[++mq].l),read(q[mq].r);
q[mq].Id=mq,q[mq].lstc=mc;
}
else {
read(c[++mc].x),read(c[mc].v);
}
}
cc=(int)pow(n,2.0/3);
sort(q+1,q+mq+1,cmp);
int L=1,R=0,T=0;
for(int i=1;i<=mq;i++) {
while(L>q[i].l) Add(a[--L]);
while(L<q[i].l) Del(a[L++]);
while(R>q[i].r) Del(a[R--]);
while(R<q[i].r) Add(a[++R]);
while(T<q[i].lstc) Work(i,++T);
while(T>q[i].lstc) Work(i,T--);
ans[q[i].Id]=s;
}
for(int i=1;i<=mq;i++) printf("%d\n",ans[i]);
return 0;
}