题目链接:点击打开链接
题意:给n个袜子, 每个袜子有一个颜色。 m次查询,每次查询给一个区间, 求在区间里的任选一对袜子的颜色相同的概率。
最经典的莫队算法, 莫队算法有两种, 我刚刚学了第一种:分块。
简单来说,假设总区间长度为n,那么将区间分成size = sqrt(n)块,那么每一块的长度为n/size,也是sqrt(n),所以每次只维护一块里的内容和块与块之间的内容,如果改变一个数的值,那么只需要改变其所在的那一块就行了,最多遍历sqrt(n)次,如果要进行区间查询,那么首先要遍历完全在区间中的每一块的信息,复杂度最高O(sqrt(n)), 然后遍历在两边的不完全被包含的部分,也是sqrt(n),所以总的复杂度就是O(sqrt(n))。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; const double PI = acos(-1.0); const double eps = 1e-6; const int mod = 1000000000 + 7; const int INF = 1000000000; const int maxn = 50010; int T,n,m,unit,a[maxn]; ll vis[maxn]; struct node { int l, r, id; bool operator < (const node& rhs) const { if(l/unit != rhs.l/unit) return l/unit < rhs.l/unit; else return r/unit < rhs.r/unit; } }node[maxn]; struct Ans { ll a, b; }ans[maxn]; ll gcd(ll a, ll b) { if(b == 0) return a; return gcd(b, a%b); } void solve() { ll cur = 0; memset(vis, 0, sizeof(vis)); int l = 1, r = 0; for(int i=0;i<m;i++) { int L = node[i].l, R = node[i].r; while(r < R) { r++; cur -= (ll)vis[a[r]] * (vis[a[r]]-1); vis[a[r]]++; cur += (ll)vis[a[r]] * (vis[a[r]]-1); } while(r > R) { cur -= (ll)vis[a[r]] * (vis[a[r]]-1); vis[a[r]]--; cur += (ll)vis[a[r]] * (vis[a[r]]-1); r--; } while(l < L) { cur -= (ll)vis[a[l]] * (vis[a[l]]-1); vis[a[l]]--; cur += (ll)vis[a[l]] * (vis[a[l]]-1); l++; } while(l > L) { l--; cur -= (ll)vis[a[l]] * (vis[a[l]]-1); vis[a[l]]++; cur += (ll)vis[a[l]] * (vis[a[l]]-1); } ll len = r - l + 1; ans[node[i].id].a = cur; ans[node[i].id].b = len * (len-1); ll g = gcd(ans[node[i].id].a,ans[node[i].id].b); ans[node[i].id].a /= g; ans[node[i].id].b /= g; } } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=0;i<m;i++) { scanf("%d%d",&node[i].l,&node[i].r); node[i].id = i; } unit = floor(sqrt(n)); sort(node, node+m); solve(); for(int i=0;i<m;i++) { printf("%lld/%lld\n",ans[i].a,ans[i].b); } } return 0; }