1. 程式人生 > >求一個區間裡的一個x,這個x與這區間裡面的所有數都互質

求一個區間裡的一個x,這個x與這區間裡面的所有數都互質

連結:https://ac.nowcoder.com/acm/contest/301/H
來源:牛客網

題描述

小樂樂上了一節數學課,數學老師講的很好,小樂樂聽的也如痴如醉。
小樂樂聽了老師的講解,知道了什麼是素數,現在他想做幾個習題。
現在題目來了:
首先我們先定義孤獨的數:在一個區間中的一個數字x,如果他與這個區間中的任何數都互質,那麼他就是孤獨的數。
我們給定一個序列,然後接下來會有多次詢問,對於每次詢問,給定兩個整數l, r,我想知道對於(a[l], a[l + 1], ...., a[r])區間來說中有多少孤獨的數。   分析:戴普 ,現在先當模板
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
const int MaxN = 1e5;
using namespace std;
 
int n, m, tot;
int a[MaxN + 5], pri[MaxN + 5];
int pre[MaxN + 5], last[MaxN + 5], c[MaxN + 5];
vector <int> V[MaxN + 5
], g[MaxN + 5]; int res[MaxN + 5]; bool vis[MaxN + 5]; struct NODE { int l, r, id; bool operator < (const NODE A) const { return l < A.l; } }query[MaxN + 5], seg[MaxN + 5]; bool cmp(NODE A, NODE B) { return A.r < B.r; } void Init() { for (int i = 2; i <= MaxN; i++) {
if(!vis[i]) pri[++tot] = i; for (int j = 1; j <= tot && i * pri[j] <= MaxN; j++) { vis[i * pri[j]] = 1; if(i % pri[j] == 0) break; } } for (int i = 1; i <= tot; i++) { for (int j = pri[i]; j <= MaxN; j += pri[i]) V[j].push_back(pri[i]); } } void Add(int x, int w) { if(x == 0) return; for (int i = x; i <= MaxN; i += (i & (-i))) c[i] += w; } int Sigma(int x) { int res = 0; for (int i = x; i > 0; i -= (i & (-i))) res += c[i]; return res; } int main() { Init(); while(~scanf("%d%d", &n, &m)) { memset(c, 0, sizeof(c)); memset(pre, 0, sizeof(pre)); g[n + 1].clear(); for (int i = 1; i <= n; i++) scanf("%d", &a[i]), g[i].clear(); for (int i = 1; i <= n; i++) { if(a[i] == 1) { seg[i].l = 0; } else { int Max = 0; for (int v : V[a[i]]) Max = max(Max, pre[v]); seg[i].l = Max; for (int v : V[a[i]]) pre[v] = i; } } for (int i = 0; i <= MaxN; i++) last[i] = n + 1; for (int i = n; i >= 1; i--) { if(a[i] == 1) seg[i].r = n + 1; else { int Min = n + 1; for (int v : V[a[i]]) Min = min(Min, last[v]); seg[i].r = Min; for (int v : V[a[i]]) last[v] = i; } } for (int i = 1; i <= n; i++) g[seg[i].r].push_back(i); for (int i = 1; i <= m; i++) scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i; sort (query + 1, query + m + 1, cmp); int l = 0; for (int i = 1; i <= m; i++) { while(l + 1 <= n && l + 1 <= query[i].r) { Add(seg[l + 1].l, 1); for (int v : g[l + 1]) { Add(seg[v].l, -1); Add(v, 1); } l++; } res[query[i].id] = query[i].r - query[i].l + 1 - Sigma(query[i].r) + Sigma(query[i].l - 1); } for (int i = 1; i <= m; i++) printf("%d\n", res[i]); } return 0; }
View Code

 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N = 1e5+7;
int w[N],l[N],r[N];//l[i],r[i]儲存第i個數的質因子出現的最左位置以及最右位置
vector<int>V[N];//V[i]儲存的是j,其中r[j]=i
vector<int>have[N],VPrime;//have[i]儲存的是數字i分解的質因子,VPrime儲存的是[1,200000]的素數
int ans[N];//儲存結果
int flag[N];
struct node
{
    int left,right,id;
}p[N];
int cmp(node aa,node bb)
{
    return aa.right<bb.right;
}
int ar[N];
int lowb(int t)
{
    return t&(-t);
}
void add(int i,int v)
{
    if(i==0) return;
    for(;i<N;ar[i]+=v,i+=lowb(i));
}
int sum(int i)
{
    int s=0;
    for(;i>0;s+=ar[i],i-=lowb(i));
    return s;
}
void getHave(int index,int v)
{
    int i=0;
    while(v>1&&i<VPrime.size())
    {
        if(VPrime[i]*VPrime[i]>v)
        {
            have[index].push_back(v);
            break;
        }
        if(i<VPrime.size()&& v%VPrime[i]==0)
        {
            have[index].push_back(VPrime[i]);
        }
        while(i<VPrime.size()&& v%VPrime[i]==0)
        {
            v/=VPrime[i];
        }
        i++;
    }
}
bool prime[N];
void init()
{
    int i,j;
    memset(prime,0,sizeof(prime));
    prime[1]=prime[0]=1;
    for(i=2;i<=N-2;i++)
        for(j=2;i*j<=N-2;j++)
        {
            prime[i*j]=1;
        }
    VPrime.clear();
    for(i=2;i<=N-2;i++)
    {
        if(prime[i]==0)
            VPrime.push_back(i);
    }
    for(i=0;i<N;i++)
    {
        have[i].clear();
    }
    for(i=2;i<N;i++)
    {
        getHave(i,i);
    }
}
void init2(int n)//計算出l陣列,r陣列以及V[]
{
    for(int i=0;i<=n;i++)
    {
        V[i].clear();
    }
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    memset(flag,0,sizeof(flag));
    for(int i=1;i<=n;i++)
    {
        int left=0;
        for(int j=0;j<have[w[i]].size();j++)
        {
            left=max(left,flag[have[w[i]][j]]);
        }
        l[i]=left;
        for(int j=0;j<have[w[i]].size();j++)
        {
            flag[have[w[i]][j]]=i;
        }
    }
    for(int i=1;i<N;i++)//這裡要初始化為n+1
    {flag[i]=n+1;}
    for(int i=n;i>=1;i--)
    {
        int right=n+1;
        for(int j=0;j<have[w[i]].size();j++)
        {
            right=min(right,flag[have[w[i]][j]]);
        }
        r[i]=right;
        for(int j=0;j<have[w[i]].size();j++)
        {
            flag[have[w[i]][j]]=i;
        }
    }
    for(int i=1;i<=n;i++)
    {
        V[r[i]].push_back(i);
    }
}
int main()
{
    int i,j,k;
    int n,m,t;
    init();
    while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0))
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d",&w[i]);
        }
        init2(n);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&p[i].left,&p[i].right);
            p[i].id=i;
        }
        sort(p+1,p+1+m,cmp);
        memset(ar,0,sizeof(ar));
        i=1;
        for(j=1;j<=m;j++)
        {
            while(i<=p[j].right)
            {
                add(l[i],1);//將左邊notFit的+1
                for(k=0;k<V[i].size();k++)
                {
                    add(l[V[i][k]],-1);//將左邊跟右邊同時notFit的-1,去掉重複
                    add(V[i][k],1);//將右邊notFit的+1
                }
                i++;
            }
            int notFit=sum(p[j].right)-sum(p[j].left-1);
            ans[p[j].id]=p[j].right-p[j].left+1-notFit;
        }
        for(i=1;i<=m;i++)
        {
            printf("%d\n",ans[i]);
        }
    }
    return 0;
}
View Code