【BZOJ 2038】小Z的袜子&莫队算法详解
2017-04-17 11:33
295 查看
莫队算法裸题
显然对于一个区间[l,r],可以在O(1)的时间里转移到[l,r+1]或[l,r-1]。
证明:
ans=∑(sum(i)∗(sum(i)−1)/2)(R−L+1)∗(R−L)/2
其中sum(i)表示第i种颜色的袜子的数量,把这个式子化简得到:
ans=∑sum(i)2−(R−L+1)(R−L+1)∗(R−L)
这样我们只要统计p = ∑sum(i)2就可以了。当某一种袜子的颜色从c变成c+1时,p=p−c2+(c+1)2=p+2∗c+1,同理从c变成c-1时,p=p+c2−(c+1)2=p−2∗c−1。也许位运算会快那么一点?(划掉)
然后对整个区间分块,对所有查询双关键字排序,第一关键字为所在的块,第二关键字是查询右端点。然后一个一个加减区间即可。
时间复杂度证明:
左端点的证明:
1、两个查询的左端点在同一块中:每次最多移动N−−√次,一共N次,时间复杂度为O(NN−−√);
2、两个查询不在同一块中:每次跨越相邻块最多要移动2N−−√次,这样的操作最多只有N−−√次,所以时间复杂度为O(N−−√2)。
右端点的证明:
1、两个查询的左端点在同一块中:右端点递增,一共移动N次,一共有N−−√块,时间复杂度为O(NN−−√);
2、两个查询不在同一块中:每次跨越相邻块右端点重新回到左侧,最多移动N次,这样的操作最多只有N−−√次,所以时间复杂度为O(NN−−√)。
显然对于一个区间[l,r],可以在O(1)的时间里转移到[l,r+1]或[l,r-1]。
证明:
ans=∑(sum(i)∗(sum(i)−1)/2)(R−L+1)∗(R−L)/2
其中sum(i)表示第i种颜色的袜子的数量,把这个式子化简得到:
ans=∑sum(i)2−(R−L+1)(R−L+1)∗(R−L)
这样我们只要统计p = ∑sum(i)2就可以了。当某一种袜子的颜色从c变成c+1时,p=p−c2+(c+1)2=p+2∗c+1,同理从c变成c-1时,p=p+c2−(c+1)2=p−2∗c−1。也许位运算会快那么一点?(划掉)
然后对整个区间分块,对所有查询双关键字排序,第一关键字为所在的块,第二关键字是查询右端点。然后一个一个加减区间即可。
时间复杂度证明:
左端点的证明:
1、两个查询的左端点在同一块中:每次最多移动N−−√次,一共N次,时间复杂度为O(NN−−√);
2、两个查询不在同一块中:每次跨越相邻块最多要移动2N−−√次,这样的操作最多只有N−−√次,所以时间复杂度为O(N−−√2)。
右端点的证明:
1、两个查询的左端点在同一块中:右端点递增,一共移动N次,一共有N−−√块,时间复杂度为O(NN−−√);
2、两个查询不在同一块中:每次跨越相邻块右端点重新回到左侧,最多移动N次,这样的操作最多只有N−−√次,所以时间复杂度为O(NN−−√)。
#include<cmath> #include<cstdio> #include<vector> #include<queue> #include<cstring> #include<iomanip> #include<stdlib.h> #include<iostream> #include<algorithm> #define ll long long #define inf 1000000000 #define mod 1000000007 #define N 100000 #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) using namespace std; struct query{int l,r,id;} q ; int block_pos ,sum ,c ; ll resa ,resb ; int n,m,i,block,l,r,p; ll ans,k; ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);} bool cmp(const query &a,const query &b) { if (block_pos[a.l] == block_pos[b.l]) return a.r < b.r; return a.l < b.l; } void update(int p,int delta) { ans = ans + (sum[c[p]] * 2 + delta) * delta; sum[c[p]] += delta; } int main() { scanf("%d%d",&n,&m); fo(i,1,n) scanf("%d",&c[i]); fo(i,1,m) scanf("%d%d",&q[i].l,&q[i].r); fo(i,1,m) q[i].id = i; block = sqrt(n); fo(i,1,n) block_pos[i] = (i - 1) / block + 1; sort(q+1,q+m+1,cmp); l = 1; r = 0; fo(i,1,m) { while (r < q[i].r) {update(r+1,1); r++;} while (r > q[i].r) {update(r,-1); r--;} while (l < q[i].l) {update(l,-1); l++;} while (l > q[i].l) {update(l-1,1); l--;} p = q[i].id; resa[p] = ans - (q[i].r - q[i].l + 1); resb[p] = (ll)(q[i].r - q[i].l + 1) * (q[i].r - q[i].l); k = gcd(resa[p],resb[p]); resa[p] /= k; resb[p] /= k; } fo(i,1,m) printf("%lld/%lld\n",resa[i],resb[i]); return 0; }
相关文章推荐
- [BZOJ 2038] 2009国家集训队 小Z的袜子 · 莫队算法
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)&&莫队算法
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose)【莫队算法裸题&&学习笔记】
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) 【莫队算法】
- BZOJ 2038([2009国家集训队]小Z的袜子(hose)-莫队算法序列)
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队算法
- bzoj 2038 小Z的袜子 [莫队算法] [概率]
- BZOJ 2038 2009国家集训队 小Z的袜子 莫队算法
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- bzoj 2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- BZOJ 2038: [2009国家集训队]小Z的袜子(hose) [莫队算法]【学习笔记】
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 莫队算法
- BZOJ2038 [2009国家集训队]小Z的袜子(hose)(莫队算法)
- 小Z的袜子(hose) - bzoj 2038 莫队算法
- BZOJ 2038 小Z的袜子(hose) 莫队算法
- BZOJ 2038 小Z的袜子(hose)(莫队算法)
- BZOJ 2038 小Z的袜子 莫队算法
- bzoj 2038: [2009国家集训队]小Z的袜子(hose) 【莫队算法】
- BZOJ 2038 小Z的袜子(hose)(莫队算法)
- bzoj 2038 A-小Z的袜子[hose] - 莫队算法