美團codem 數列互質 - 莫隊

題目描述

給出一個長度爲 nnn 的數列 a1,a2,a3,...,an{ a_1 , a_2 , a_3 , ... , a_n }a1​​,a2​​,a3​​,...,an​​,以及 mmm 組詢問 (li,ri,ki)( l_i , r_i , k_i)(li​​,ri​​,ki​​),求區間 [li,ri][ l_i , r_i ][li​​,ri​​] 中有多少數在該區間中的出現次數與 kik_iki​​ 互質。html

輸入格式

第一行,兩個正整數 n,mn , mn,m。node

第二行,nnn 個正整數 aia_iai​​ 描述這個數列。git

接下來 mmm 行,每行三個正整數 li,ri,kil_i , r_i , k_ili​​,ri​​,ki​​,描述一次詢問。ui

輸出格式

輸出 mmm 行,即每次詢問的答案。spa

樣例

樣例輸入

10 5
1 1 1 1 1 2 2 2 2 2
4 7 2
4 7 3
4 8 2
4 8 3
3 8 3

樣例輸出

0
2
1
1
0

數據範圍與提示

  • 1≤n,m≤5×1041\le n,m\le 5\times 10^41n,m5×104​​
  • 1≤ai≤n1\le a_i\le n1ai​​n
  • 1≤li≤ri≤n1\le l_i\le r_i\le n1li​​ri​​n
  • 1≤ki≤n1\le k_i\le n1ki​​n

 

思路分析 : 莫隊基本題目,暴力維護的區間的元素有區間內不一樣元素的出現次數,同時再記錄一下出現不一樣的次數有多少次,記錄一下某個區間不一樣次數的種類,相似鏈表code

    複雜度 :某個區間不一樣元素的次數種類最多有 根號n 種,總的複雜度就是 n*sqrt(n)*log(n)htm

    寫的時候有個地方寫錯了,就是分塊的排序的地方... 一直TLEblog

代碼示例 :排序

using namespace std;
#define ll long long
const int maxn = 5e4+5;
const int mod = 1e9+7;
const double eps = 1e-9;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;

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 n, m;
struct node
{
    int zu;
    int l, r, k, id;
    
    bool operator< (const node &v)const{
        if (zu == v.zu) return r < v.r;
        return l < v.l;
    }
}a[maxn];
int pre[maxn], cnt[maxn];
int num[maxn], time2[maxn<<2];
int all;
bool pt[maxn<<2];
int ans[maxn];

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

inline void remove(int x){
    cnt[x]--;
    num[cnt[x]]++, num[cnt[x]+1]--;
    time2[all++] = cnt[x];
}

inline void add(int x){
    cnt[x]++;
    num[cnt[x]]++, num[cnt[x]-1]--;
    time2[all++] = cnt[x];
}

int main() {
    int l, r, k;
    
    cin >> n >> m;
    int unit = sqrt(n);
    for(int i = 1; i <= n; i++) pre[i] = read();
    for(int i = 1; i <= m; i++){
        l = read(), r = read(), k = read();
        //scanf("%d%d%d", &l, &r, &k);
        int f = (l-1)/unit+1;
        a[i] = {f, l, r, k, i}; 
    }
    sort(a+1, a+1+m);
    
    l = a[1].l, r = a[1].l-1; 
    all = 1; int sum = 0;
    for(int i = 1; i <= m; i++){ 
        while(l < a[i].l) remove(pre[l++]);
        while(r > a[i].r) remove(pre[r--]);
        while(l > a[i].l) add(pre[--l]);
        while(r < a[i].r) add(pre[++r]); 
        k = 1; sum = 0; 
        for(int j = 1; j < all; j++){
            if (!pt[time2[j]] && num[time2[j]] > 0){
                if (gcd(time2[j], a[i].k) == 1) {
                    sum += num[time2[j]];
                }
                time2[k++] = time2[j];
                pt[time2[j]] = true;
            }
        }
        all = k;
        ans[a[i].id] = sum;
        for(int j = 1; j < k; j++) pt[time2[j]] = false;
    }
    for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
    return 0;
}
相關文章
相關標籤/搜索