zoukankan      html  css  js  c++  java
  • AcWing 251 小Z的袜子 (莫队)

    题目链接:https://www.acwing.com/problem/content/description/253/

    莫队算法:对询问分块
    先将询问按左端点递增排序,然后将询问分成 (sqrt{n}) 块,块内再将询问按右端点递增排序
    块内相邻左端点变化不会超过 (sqrt{n}) ,而右端点变化之和为 (n)
    所以复杂度是 (O(nsqrt{n}))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 100010;
    
    int n, m, t, len, tot;
    int c[maxn], b[maxn], L[maxn], R[maxn], pos[maxn], cnt[maxn];
    ll ans;
    
    struct Q{
    	int id;
    	int L, R;
    	ll ans;
    }q[maxn];
    
    bool cmp_L(Q a, Q b){
    	if(a.L == b.L) return a.R < b.R;
    	return a.L < b.L;
    }
    
    bool cmp_R(Q a, Q b){
    	if(a.R == b.R) return a.L < b.L;
    	return a.R < b.R;
    }
    
    bool cmp_id(Q a, Q b){
    	return a.id < b.id;
    }
    
    void add(int i){
    	ans -= 1ll * cnt[c[i]] * (cnt[c[i]] - 1) / 2;
    	++cnt[c[i]];
    	ans += 1ll * cnt[c[i]] * (cnt[c[i]] - 1) / 2;
    }
    
    void del(int i){
    	ans -= 1ll * cnt[c[i]] * (cnt[c[i]] - 1) / 2;
    	--cnt[c[i]];
    	ans += 1ll * cnt[c[i]] * (cnt[c[i]] - 1) / 2;
    }
    
    ll gcd(ll a, ll b){ return b ? gcd(b, a % b) : a; }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	ans = 0;
    	n = read(), m = read(); 
    	t = sqrt(n); len = m / t;
    	//分块预处理 
    	for(int i = 1; i <= t; ++i){
    		L[i] = (i - 1) * len + 1;
    		R[i] = i * len;
    	}
    	
    	for(int i = 1; i <= t; ++i){
    		for(int j = L[i] ; j <= R[i]; ++j){
    			pos[j] = i;
    		}
    	}
    	if(R[t] < m){ ++t; L[t] = R[t - 1] + 1; R[t] = m; }
    	//
    	
    	// 离散化 
    	for(int i = 1; i <= n ; ++i) c[i] = read(), b[i] = c[i];
    	
    	sort(b + 1, b + 1 + n);
    	tot = unique(b + 1, b + 1 + n) - b - 1;
    	for(int i = 1 ; i <= n; ++i) c[i] = lower_bound(b + 1, b + 1 + tot, c[i]) - b; 
    	
    	
    	for(int i = 1; i <= m; ++i){
    		q[i].L = read(), q[i].R = read();
    		q[i].id = i;
    	}
    	
    	sort(q + 1, q + 1 + m, cmp_L);
    
    	int cl, cr;
    	for(int i = 1; i <= t; ++i){
    		memset(cnt, 0 ,sizeof(cnt));
    		ans = 0;
    		sort(q + L[i], q + 1 + R[i], cmp_R);
    		
    		int ql = q[L[i]].L, qr = q[L[i]].R; cl = ql, cr = qr;
    		for(int j = ql; j <= qr; ++j) ++cnt[c[j]];
    		
    		for(int j = 1; j <= tot; ++j) ans += cnt[j] * (cnt[j] - 1) / 2; 
    		
    		q[L[i]].ans = ans;
    		
    		for(int j = L[i] + 1; j <= R[i]; ++j){
    			ql = q[j].L, qr = q[j].R;
    			while(cl > ql) add(cl - 1), --cl;
    			while(cl < ql) del(cl), ++cl;
    			while(cr < qr) add(cr + 1), ++cr;
    			
    			q[j].ans = ans;
    		}
    	} 
    	
    	sort(q + 1, q + 1 + m, cmp_id);
    	
    	for(int i = 1; i <= m; ++i){
    		ll A = q[i].ans, B = q[i].R - q[i].L + 1;
    		B = 1ll * B * (B - 1) / 2;
    		ll gc = gcd(A, B);
    		
    		if(A == 0) printf("0/1
    ");
    		else printf("%lld/%lld
    ", A / gc, B / gc);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    VUE的生命周期
    ID生成算法(二)
    ID生成算法(一)——雪花算法
    HTTP状态码和支持的方法
    水平居中/垂直居中/水平垂直居中总结
    判断数组类型的4种方法
    WebSocket浅谈
    vue中使用定时器时this指向
    银行转账业务梳理
    支付那些事儿
  • 原文地址:https://www.cnblogs.com/tuchen/p/13962783.html
Copyright © 2011-2022 走看看