美团CodeM 初赛 A轮 数列互质 莫队

来源:互联网 发布:java开源代码论坛 编辑:程序博客网 时间:2024/06/08 14:13

题目链接点这里

应该很容易想到用莫队做,然后那?我们现在已经知道了一个区间内各个数出现的次数,及其次数出现的次数,我们应该怎么算他互质的数的个数?我们先要知道这么一个事实,

一个区间内次数的不同最多是sqrt(n)个,,所以整个算法的复杂度是,,nsqrt(n)(莫队的)+msqrt(n)*(求互质的复杂度)

这个(求互质的复杂度),,一般有三种方法,,第一种直接logn求gcd。。第二种现将k的质因子找到,然后对于每个次数试除k的质因子看看能不能整除。。。第三种是用玄学O(1)的gcd。。

我三种都写了一下,,,最快的是第二种,第一种和第三种速度差不多。。

我的解释是O(1)的gcd常数过大,并且这道题的数据太小才5*10^4,对于第一种方法最多在14次之内求出gcd,可以认为常数为14。对于第二种质因子数最多才7个,常数为7。对于第三种,常数不是很算的清,但是可以知道很大。所以O(1)gcd的效果不明显。。。如果数据为100W,,第三种的速度就体现了,因为第三种的常数是固定的。前两种的常数和数据范围成正比。

下面就贴一个第三种的写法吧,,前两种大家应该很熟悉了

题外话:这个loj很不错啊,

#include<iostream>#include<cstdio>#include<math.h>#include<algorithm>#include<map>#include<set>#include<bitset>#include<unordered_map>#include<stack>#include<queue>#include<string.h>#include<cstring>#include<vector>#include<time.h>#include<stdlib.h>using namespace std;#define INF 0x3f3f3f3f#define INFLL 0x3f3f3f3f3f3f3f3f#define FIN freopen("input.txt","r",stdin)#define mem(x,y) memset(x,y,sizeof(x))typedef unsigned long long ULL;typedef long long LL;#define fuck(x) cout<<"q"<<endl;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef pair<pair<int,int>,int> PIII;typedef pair<int,int> PII;const double eps=1e-8;#define MX 111111#define MK 444bool isprime[MX];int prime[MX];int G[MK+5][MK+5];int s[MX][3];void gcd_init(){    s[1][0]=s[1][1]=s[1][2]=1;    mem(isprime,1);    prime[0]=0;    for(int i=2; i<MX; i++)    {        if(isprime[i])        {            prime[++prime[0]]=i;            s[i][0]=i;            s[i][1]=s[i][2]=1;        }        for(int j=1; j<=prime[0]&&i*prime[j]<MX; j++)        {            int v=i*prime[j];            for(int k=0; k<3; k++)s[v][k]=s[i][k];            if(s[v][0]*prime[j]<MK)s[v][0]*=prime[j];            else if(s[v][1]*prime[j]<MK)s[v][1]*=prime[j];            else s[v][2]*=prime[j];            isprime[v]=0;            if(i%prime[j]==0)break;        }    }    for(int i=1; i<MK; i++)        for(int j=0; j<i; j++)if(!j)G[i][j]=i;            else G[i][j]=G[j][i]=G[j][i%j];}int Gcd(int x,int y){    if(!x||!y)return x+y;    if(x<MK&&y<MK)return G[x][y];    int ans=1,d;    for(int i=0; i<3; i++)    {        if(s[x][i]==1)continue;        else if(s[x][i]<MK)d=G[s[x][i]][y%s[x][i]];        else if(y%s[x][i]==0)d=s[x][i];        else d=1;        y/=d;        ans*=d;    }    return ans;}int n,m;int block;int w[MX];struct Q{    int l,r,k,id;    bool operator <(const Q a)const    {        if(l/block!=a.l/block)return l/block<a.l/block;        return r/block<a.r/block;    }} q[MX];int ans[MX];int cnt[MX];int num[MX];int path[MX];void Delete(int v){    num[cnt[v]--]--;    path[++path[0]]=cnt[v];    num[cnt[v]]++;}void Insert(int v){    num[cnt[v]++]--;    path[++path[0]]=cnt[v];    num[cnt[v]]++;}int g[MX];int vis[MX];int solve(int k){    if(k==1)k=57223;    g[0]=0;    int ans=0;    int tmp=0;    for(int i=1; i<=path[0]; i++)        if(num[path[i]]&&vis[path[i]]==0)        {            vis[path[i]]=1;            int flag=1;            // for(int j=1; j<=g[0]; j++)if(path[i]%g[j]==0)flag=0;            if(Gcd(k,path[i])==1)ans+=num[path[i]];            path[++tmp]=path[i];        }    for(int i=1; i<=tmp; i++)vis[path[i]]=0;    path[0]=tmp;    return ans;}inline int read(){    int ret=0,c,f=1;    for(c=getchar(); !(isdigit(c)||c=='-'); c=getchar());    if(c=='-') f=-1,c=getchar();    for(; isdigit(c); c=getchar()) ret=ret*10+c-'0';    if(f<0) ret=-ret;    return ret;}int main(){    gcd_init();    // prime_init();    FIN;    while(cin>>n>>m)    {        mem(cnt,0);        block=sqrt(n+0.5);        for(int i=1; i<=n; i++)w[i]=read();        for(int i=1; i<=m; i++)        {            q[i].l=read(),q[i].r=read(),q[i].k=read();            q[i].id=i;        }        sort(q+1,q+1+m);        int l=0,r=0;        cnt[0]=1;        num[1]=1;        path[0]=1;        path[1]=0;        for(int i=1; i<=m; i++)        {            while(l<q[i].l)Delete(w[l++]);            while(l>q[i].l)Insert(w[--l]);            while(r<q[i].r)Insert(w[++r]);            while(r>q[i].r)Delete(w[r--]);            ans[q[i].id]=solve(q[i].k);        }        for(int i=1; i<=m; i++)printf("%d\n",ans[i]);    }    return 0;}