zoukankan      html  css  js  c++  java
  • 莫队/se 优雅的暴力

    莫队算法

    发明者:队爷莫涛
    基于分块的一种暴力算法, 复杂度最慢可以被卡到(n^2)正常情况下的复杂度大约在(O(nsqrt{n}))左右分块的大小对复杂的影响很大其中最优分块的大小为(dfrac {s}{sqrt{m}}) 最优复杂度为(O(nsqrt{m}))

    证明

    用处:维护区间信息

    具体做法

    • 对求的(l-r)区间进行排序,根据(l)(r)所在块的位置,进行排序
    • 对排序后的(l-r)的区间进行维护,观察维护的数据具有什么特点

    注意:

    • 4个(while)循环不能乱,根据先后关系进行确定(24中全排列,6中正确)
    • 莫队比较卡常,注意写小常数
      例题
      这个就是概率问题
    • 例子1 eg:3 3 4 5 6 4
      (ans = dfrac{2}{6} imes dfrac{1}{5} + dfrac{2}{6} imes dfrac{1}{5} = dfrac{2}{15})
      莫队的过程就是
    l = 1 ,r = 0 ,son = 0
    l = 1 ,r = 1 ,son = 0 
    l = 1 ,r = 2 ,son = 2 * ( 2 - 1 ) / 2
    l = 1 ,r = 3 ,son = 2 * ( 2 - 1 ) / 2
    l = 1 ,r = 4 ,son = 2 * ( 2 - 1 ) / 2
    l = 1 ,r = 5 ,son = 2 * ( 2 - 1 ) / 2
    l = 1 ,r = 6 ,son = 2 * ( 2 - 1 ) / 2 + 2 * (2 - 1) / 2
    mo = 6 * (6 - 1) / 2
    
    • 例子1 eg: 3 3 3 4 5 6 4
    l = 1 ,r = 0 ,son = 0
    l = 1 ,r = 1 ,son = 2 * ( 2 - 1 ) / 2
    l = 1 ,r = 2 ,son = 3 * ( 3 - 1 ) / 2
    l = 1 ,r = 3 ,son = 3 * ( 3 - 1 ) / 2
    l = 1 ,r = 4 ,son = 3 * ( 3 - 1 ) / 2
    l = 1 ,r = 5 ,son = 3 * ( 3 - 1 ) / 2
    l = 1 ,r = 6 ,son = 3 * ( 3 - 1 ) / 2 + 2 * (2 - 1) / 2
    mo = 7 * (7 - 1) / 2
    

    过程中先删去前一个的贡献再加上后一个的贡献

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <algorithm>
    #define orz puts("LKP AK IOI")
    #define ll long long
    using namespace std;
    const int N = 5e4+100;
    int read(){
    	int 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;
    }
    ll sqrtn , l = -1, r = 0, ans;
    ll son[N], mo[N];
    struct node {
    	int l, r, id;
    	bool operator < (const node &x) const {
    		if( l / sqrtn != x.l / sqrtn) return l < x.l;
    		if((l/sqrtn) & 1) return r < x.r;
    		return r > x.r;  
    	}
    }wa[N];
    int cs[N],c[N];
    ll ANS(ll  x) {
    	return x < 2 ? 0: x * (x - 1) ;	
    }
    void del(int pos) {
    	ll temp = --cs[c[pos]];
    	ans -= ANS(temp+1);	ans += ANS(temp);
    } 
    void add(int pos) {
    	ll temp = ++cs[c[pos]];
    	ans -= ANS(temp-1);	ans += ANS(temp); 
    }
    ll gcd(ll a,ll b) {
    	return b == 0 ? a : gcd(b, a%b); 
    } 
    bool cmp(node a,node b) {
    	if(a.l/sqrtn == b.l/sqrtn)	return a.r < b.r;
    	return a.l < b.l; 
    }
    int main(){
    	int n = read() ,m = read()	;
    	for(int i = 1 ; i <= n ; i++) 	c[i] = read();
    	for(int i = 1 ; i <= m ;i++) 	wa[i].l = read() , wa[i].r = read() , wa[i].id = i; 
    	sqrtn = sqrt(0.5+n );
    	sort(wa+1,wa+1+m);
    	//sort(wa+1 , wa+1+m, cmp); 
    	//orz;
    	for(int i = 1 ; i <= m ;i++) {
    		while (l < wa[i].l) del(l),l++;
    		while (l > wa[i].l) l--,add(l);
    		while (r < wa[i].r) r++,add(r);
    		while (r > wa[i].r) del(r),r--;
    		son[wa[i].id] = ans;
    		mo[wa[i].id] = ANS(r-l+1);
    	}
    	for(int i = 1; i <= m ;i++) {
    		if(son[i] == 0) {
    			cout<<"0/1
    ";
    			continue;
    		}
    		ll temp = gcd(son[i],mo[i]);
    		printf("%lld/%lld
    ",son[i]/temp,mo[i]/temp);
    	}
    	return 0;
    }
    
  • 相关阅读:
    [Oracle][Partition][Controlfile]Partition 操作是否和 Controlfile有关?
    [Oracle]如何观察Table 的各种Lock 之间的冲突
    [Oralce][InMemory]如何确定一个表已经被Populate 到In Memory 中?
    Arduino和C51之串口通信
    XC文件管理器-打造优美易用的文件管理器
    Android 控件进阶修炼-仿360手机卫士波浪球进度控件
    Android控件进阶-自定义流式布局和热门标签控件
    Windows开发之VC++仿QQ迷你首页(迷你资讯)
    Android自定义控件进阶-打造Android自定义的下拉列表框控件
    Android 自定义控件-高仿猎豹清理大师自定义内存开口圆环控件
  • 原文地址:https://www.cnblogs.com/-wzd233/p/14130648.html
Copyright © 2011-2022 走看看