题面

Bzoj

洛谷

题解

考虑莫队算法,首先对询问进行分块(分块大小为$sqrt(n)$),对于同一个块内的询问,按照左端点为第一关键字,右端点为第二关键字排序。我们统计这个区间内相同的颜色有多少个,假设某种颜色$i$有$j$个,则贡献就是$j\times(j-1)$,最后记得化成既约分数。

#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
typedef long long ll;
using std::set; template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
} const int N = 5e4 + 10, M = 5e4 + 10;
int n, m, c[N], siz, blo, t, l, r, v[N];
struct Ques { int x, y, z; } q[M], b[M];
inline bool cmp1 (Ques a, Ques b) { return a.x < b.x; }
inline bool cmp2 (Ques a, Ques b) { return a.y < b.y; }
ll up[M], down[M], _gcd, tmp;
template<typename T>
T gcd(T a, T b) { return b ? gcd(b, a % b) : a; } void modify (int st, int ed, int flag) {
for(int i = st; i < ed; ++i) {
tmp -= 1ll * v[c[i]] * (v[c[i]] - 1);
v[c[i]] += flag;
tmp += 1ll * v[c[i]] * (v[c[i]] - 1);
}
} int main () {
#ifdef OFFLINE_JUDGE
freopen("233.in", "r", stdin);
freopen("233.out", "w", stdout);
#endif
read(n), read(m);
for(int i = 1; i <= n; ++i) read(c[i]);
for(int i = 1; i <= m; ++i)
read(q[i].x), read(q[i].y), q[i].z = i;
sort(&q[1], &q[m + 1], cmp1);
siz = sqrt(n), blo = (n / siz) + (n % siz != 0);
for(int i = 0, j = 1; i < blo; ++i) {
t = 0;
while(j <= m && q[j].x > i * siz && q[j].x <= (i + 1) * siz) b[++t] = q[j++];
sort(&b[1], &b[t + 1], cmp2);
l = b[1].x, r = b[1].x - 1, tmp = 0;
memset(v, 0, sizeof v);
for(int k = 1; k <= t; ++k) {
if(b[k].x == b[k].y) {
up[b[k].z] = 0, down[b[k].z] = 1;
continue;
}
if(l < b[k].x) modify(l, b[k].x, -1);
else if(l > b[k].x) modify(b[k].x, l, 1);
if(r < b[k].y) modify(r + 1, b[k].y + 1, 1);
else if(r > b[k].y) modify(b[k].y + 1, r + 1, -1);
up[b[k].z] = tmp, down[b[k].z] = b[k].y - b[k].x + 1;
l = b[k].x, r = b[k].y;
}
}
for(int i = 1; i <= m; ++i) {
if(!down[i] || !up[i]) { puts("0/1"); continue; }
down[i] = down[i] * (down[i] - 1);
tmp = gcd(up[i], down[i]);
printf("%lld/%lld\n", up[i] / tmp, down[i] / tmp);
}
return 0;
}

最新文章

  1. oracle 创建表空间
  2. Linix常用命令
  3. jQuery 写的插件图片上下切换幻灯效果
  4. Modularity模块化
  5. vijosP1016 北京2008的挂钟
  6. Android开源项目发现---ProgressBar 篇(持续更新)
  7. FreeCodeCamp:Return Largest Numbers in Arrays
  8. JavaScript 版数据结构与算法(四)集合
  9. bzoj4011[HNOI2015]落忆枫音 dp+容斥(?)
  10. Web开发技术的演变
  11. Java 中数字和字符串拼接的问题
  12. cms建站
  13. pytorch bug: for step,data in enumerate(loader)+Connection reset by peer
  14. SQL update select结合语句详解及应用
  15. IIS 6的日志time-taken字段没有值的解决方案
  16. Hadoop框架
  17. (转)丢掉鼠标吧,使用最好用的eclipse快捷键
  18. Java设计模式(1)工厂模式(Factory模式)
  19. Chapter 3. Lexical Structure
  20. JavaWeb中监听器

热门文章

  1. 【Java-GUI】homework~QQ登录界面
  2. 给APP增加RSA签名
  3. javascript在IE下不能用 trim函数解决方法
  4. [php]referer应用--http防盗链技术
  5. 【洛谷 P4166】 [SCOI2007]最大土地面积(凸包,旋转卡壳)
  6. 【zTree】zTree展开树节点
  7. Django【进阶】modelform
  8. sendEmail实现邮件报警
  9. insta php-fpm 的配置
  10. 窗口生效函数UpdateData