BZOJ2038 小Z的袜子(莫队之源)
题意+思路:
给你m个区间询问,问每个区间内的$\displaystyle \frac{\sum x^2-(R-L+1)}{(R-L)(R-L+1)} $,其中x为每种数字的个数,用cnt存储;
所以我们需要用莫队处理每个区间的$\displaystyle \sum x^2 $
相邻状态转移如果是$O(i)$,复杂度就为$O(in\sqrt{n})$,因为这里状态转移是$O(1)$的,所以复杂度为$O(n\sqrt{n})$
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-5; const int mod = 1e9+7; const int maxn = 3e5+2; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); inline ll gcd(ll a, ll b){ return b==0?a:gcd(b,a%b); } int block; ll res;//存储sigma x^2 struct Blc{ int l, r; int id; bool operator < (const Blc &b)const{ if(l/block == b.l/block) return r < b.r; return l/block < b.l/block; } }blc[maxn]; int a[maxn]; ll cnt[maxn]; ll ansx[maxn], ansy[maxn];//储存答案x/y void insert(int x){ res -= cnt[x]*cnt[x]; cnt[x]++; res += cnt[x]*cnt[x]; return; } void remove(int x){ res -= cnt[x]*cnt[x]; cnt[x]--; res += cnt[x]*cnt[x]; return; } int main(){ int n, m; scanf("%d %d", &n, &m); block = sqrt(n); for(int i = 1; i <= n; i++)scanf("%d", &a[i]); for(int i = 0; i < m; i++){ blc[i].id=i; scanf("%d %d", &blc[i].l, &blc[i].r); } mem(cnt, 0); sort(blc, blc+m); int l, r; l = r = 1;//光标 cnt[a[1]]++; res = 1; for(int i = 0; i < m; i++){ int id = blc[i].id; if(blc[i].l==blc[i].r){ ansx[id] = 0; ansy[id] = 1; continue; } while(l < blc[i].l) remove(a[l++]); while(l > blc[i].l) insert(a[--l]); while(r < blc[i].r) insert(a[++r]); while(r > blc[i].r) remove(a[r--]); ll x, y, g; x = res - (blc[i].r - blc[i].l + 1); y = (blc[i].r - blc[i].l)*(blc[i].r - blc[i].l + 1ll); g = gcd(y, x); ansx[id] = x/g; ansy[id] = y/g; } for(int i = 0; i < m; i++){ printf("%lld/%lld\n", ansx[i], ansy[i]); } return 0; }