#6164. 「美团 CodeM 初赛 Round A」数列互质-莫队

#6164. 「美团 CodeM 初赛 Round A」数列互质

思路 : 对这个题来言,莫队可以 n*根号n 离线处理出各个数出现个的次数 ,同时可以得到每个次数出现的次数 ,

但是还要处理有多少 次数 与ki互质 。根据数列的性质,无论这个区间多长,最长也就是 1 - n这个区间 ,所能产生的

不同的次数 也就是 根号 n 种  例如 长度为28的 数列    1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 7 7 7 不同的次数 只有 7种 

数列越长了 这个性质体现的越明显, 原因就是 根据他们的出现的次数求个和 就算他们都按 最小的次数出现的话 1 2 3 4...s 求和为 (1+s)*s/2

而这个数又不能超过 区间长度 ,所以 这个 s也就在 根号 长度左右。 所以可以放心的进行暴力求解,有插入删除操作,可以数组模拟链表实现。

#include<bits/stdc++.h>
using namespace std;
#define maxn 55555
int n,m,cnt[maxn*2],tong[maxn*2],block,ans[maxn],data[maxn];
int nxt[maxn*2],lst[maxn*2],head=0,tail=maxn-1,l,r;
struct node
{
    int l,r,k,id;
    bool operator <(const node &b)const
    {
        return l/block==b.l/block?r<b.r:l<b.l;
    }
} a[maxn];
void upda(int rd)
{
    if(rd<=head)return;
    nxt[rd]=nxt[head];
    nxt[head]=rd;
    lst[rd]=head;
    lst[nxt[rd]]=rd;
}
void rmove(int rd)
{
    if(rd<=head)return;
    nxt[lst[rd]]=nxt[rd];
    lst[nxt[rd]]=lst[rd];
}
void ins(int x)
{
    if(--tong[cnt[x]]==0)rmove(cnt[x]);
    if(++tong[++cnt[x]]==1)upda(cnt[x]);
}
void del(int x)
{
    if(--tong[cnt[x]]==0)rmove(cnt[x]);
    if(++tong[--cnt[x]]==1)upda(cnt[x]);
}
int main()
{
    scanf("%d%d",&n,&m);
    block=sqrt(n);
    nxt[0]=tail;
    lst[tail]=0;
    for(int i=1; i<=n; i++)
        scanf("%d",&data[i]);
    for(int i=0; i<m; i++)
    {
        a[i].id=i;
        scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].k);
    }
    sort(a,a+m);
    l=a[0].l;
    r=a[0].l-1;
    for(int i=0; i<m; i++)
    {
        while(l>a[i].l)
            ins(data[--l]);
        while(l<a[i].l)
            del(data[l++]);
        while(r>a[i].r)
            del(data[r--]);
        while(r<a[i].r)
            ins(data[++r]);
        int cp=0;
        for(int j=nxt[head]; j!=tail; j=nxt[j])
            if(__gcd(a[i].k,j)==1) cp+=tong[j];
        ans[a[i].id]=cp;
    }
    for(int i=0; i<m; i++)printf("%d
",ans[i]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/SDUTNING/p/10239963.html