P1494 [国家集训队]小Z的袜子

P1494 [国家集训队]小Z的袜子

普通莫队模板题。

考虑对于任意一个区间,只需要维护平方和即可(推导题解里面就有)

中间这一段核心操作解释以下:

for(register int i=1,l=1,r=0;i<=m;++i){
        for(;r<e[i].r;++r)
            update(r+1,1);
        for(;r>e[i].r;--r)
            update(r,-1);
        for(;l<e[i].l;++l)
            update(l,-1);
        for(;l>e[i].l;--l)
            update(l-1,1);
        if(e[i].l==e[i].r){
            e[i].a=0,e[i].b=1;
            continue;
        }
        e[i].a=ans-(e[i].r-e[i].l+1);
        e[i].b=(e[i].r-e[i].l+1)*1LL*(e[i].r-e[i].l);
        ll g=gcd(e[i].a,e[i].b);
        e[i].a/=g;
        e[i].b/=g;
    }

将这一段代码分开来看。

for(;r<e[i].r;++r)
	update(r+1,1);
  • 将区间右端点少了的东西补上。
for(;r>e[i].r;--r)
	update(r,-1);
  • 将区间右端点多余的东西删去
for(;l<e[i].l;++l)
	update(l,-1);
  • 将左端点多余的东西先删去
for(;l>e[i].l;--l)
	update(l-1,1);
  • 再补上左端点少了的东西

这样反复推敲肯定不会有问题啦!

这里,我将这四段代码的顺序调为如下格式,一样能AC:

for(;r>e[i].r;--r)
	update(r,-1);
for(;r<e[i].r;++r)
	update(r+1,1);        
for(;l>e[i].l;--l)
	update(l-1,1);
for(;l<e[i].l;++l)
   update(l,-1);

说明顺序并没有任何影响。


update

1)具体\(update\)里面怎么写还是看题目为标准

2)这道题目主要是在维护区间的平方

inline void update(ll x,ll val){
    ans-=s[c[x]]*s[c[x]];
    s[c[x]]+=val;
    ans+=s[c[x]]*s[c[x]];
}

3)后面就直接跟着式子打就好了。


注意事项

1)这题目的排序有毒!尝试过以下情况:

inline int cmp(Node a,Node b){
    return a.pos!=b.pos?a.l<b.l:((a.pos&1)?a.r<b.r:a.r>b.r);
}

inline int cmp(Node at,Node az){    if(pos[at.pos]==pos[az.pos])        return at.r<az.r;    return at.l<az.l;}

(当然后面这个显然不对了)

至今原因不明。

#include <bits/stdc++.h>
#define ll long long
#define maxn 50005
using namespace std;
ll n,m,c[maxn],s[maxn];
ll lg,ans,pos[maxn];
struct Node{
    ll l,r,pos;
    ll a,b;
}e[maxn<<2];

inline ll read(){
    ll x=0,f=0;char c=getchar();
    while(!isdigit(c))
        f|=c=='-',c=getchar();
    while(isdigit(c))
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return f?-x:x;
}

inline int cmp(Node at,Node az){
    if(pos[at.l]==pos[az.l])
        return at.r<az.r;
    return at.l<az.l;
}

inline int cmp_two(Node at,Node az){
    return at.pos<az.pos;
}

inline ll gcd(ll a,ll b){
    return (b==0)?a:gcd(b,a%b);
}

inline void update(ll x,ll val){
    ans-=s[c[x]]*s[c[x]];
    s[c[x]]+=val;
    ans+=s[c[x]]*s[c[x]];
}

inline void solve(){
    for(register int i=1,l=1,r=0;i<=m;++i){
        for(;r>e[i].r;--r)
            update(r,-1);
        for(;r<e[i].r;++r)
            update(r+1,1);
        
        
        for(;l>e[i].l;--l)
            update(l-1,1);
        for(;l<e[i].l;++l)
            update(l,-1);    
        if(e[i].l==e[i].r){
            e[i].a=0,e[i].b=1;
            continue;
        }
        e[i].a=ans-(e[i].r-e[i].l+1);
        e[i].b=(e[i].r-e[i].l+1)*1LL*(e[i].r-e[i].l);
        ll g=gcd(e[i].a,e[i].b);
        e[i].a/=g;
        e[i].b/=g;
    }
}

int main(){
    n=read();m=read();
    for(register int i=1;i<=n;++i)
        c[i]=read();
    lg=sqrt(n);
    for(register int i=1;i<=n;++i)
        pos[i]=(i-1)/lg+1;
    for(register int i=1;i<=m;++i)
        e[i].l=read(),e[i].r=read(),e[i].pos=i;
    sort(e+1,e+m+1,cmp);
    solve();
    sort(e+1,e+m+1,cmp_two);
    for(register int i=1;i<=m;++i)
        printf("%lld/%lld\n",e[i].a,e[i].b);
    return 0;
}
上一篇:P1494 小Z的袜子


下一篇:2021江西 gym103366G. Magic Number Group