美團CodeM 初賽 A輪 數列互質 莫隊

題目鏈接點這裏

應該很容易想到用莫隊做,然後那?我們現在已經知道了一個區間內各個數出現的次數,及其次數出現的次數,我們應該怎麼算他互質的數的個數?我們先要知道這麼一個事實,

一個區間內次數的不同最多是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|1
typedef pair<pair<int,int>,int> PIII;
typedef pair<int,int> PII;
const double eps=1e-8;
#define MX 111111
#define MK 444
bool 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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章