P1494 [国家集训队]小Z的袜子
题目
思路
其实挺简单的一个莫队,直接把莫队模板的add()
,earse()
改改即可,另外用到一些组合数学,也不再赘述,详见代码
另外,还要注意最大数据可能超出int
范围(分子(分母)最大值约为2.5*10^10),用unsigned int
即可
代码
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define uni unsigned int
#define nn 100010
using namespace std;
int read() {
int re = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0',
c = getchar();
return re;
}
struct node{
int l , r , id;
}ask[nn];
int t;
bool cmp(node a , node b) {
return (a.l / t != b.l / t) ? (a.l / t < b.l / t) : (a.r < b.r);
}
uni num[nn];
int n , q;
uni a[nn];
uni cnt;
uni ans[nn][3];
void add(int l , int r) {
if(l == 0)++l;
if(r < l)return;
for(int i = l ; i <= r ; i++) {
if(num[a[i]] != 0)
cnt -= num[a[i]] * (num[a[i]] - 1) / 2u;
++num[a[i]];
cnt += num[a[i]] * (num[a[i]] - 1) / 2u;
}
}
void earse(int l , int r) {
if(l == 0)++l;
if(r < l)return;
for(int i = l ; i <= r ; i++) {
cnt -= num[a[i]] * (num[a[i]] - 1) / 2u;
--num[a[i]];
if(num[a[i]] != 0)
cnt += num[a[i]] * (num[a[i]] - 1) / 2u;
}
}
uni gcd(uni a , uni b){
return b == 0 ? a : gcd(b , a % b);
}
int main() {
n = read() , q = read();
for(int i = 1 ; i <= n ; i++)
a[i] = read();
int q_ = q;
for(int i = 1 , j = 0 ; i <= q ; i++) {
++j;
ask[i].l = read() , ask[i].r = read() , ask[i].id = j;
while(ask[i].l == ask[i].r && i <= q) {
ans[j][0] = 0 , ans[j][1] = 1;
--q, ++j;
if(i > q)break;
ask[i].l = read() , ask[i].r = read() , ask[i].id = j;
}
}
t = sqrt(n);
sort(ask + 1 , ask + q + 1 , cmp);
for(int i = 1 ; i <= q ; i++) {
earse(ask[i - 1].l , ask[i].l - 1);
add(ask[i - 1].r + 1 , ask[i].r);
earse(ask[i].r + 1 , ask[i - 1].r);
add(ask[i].l , ask[i - 1].l - 1);
ans[ask[i].id][0] = cnt;
ans[ask[i].id][1] = ((long long)ask[i].r - ask[i].l) * (ask[i].r - ask[i].l + 1) / 2;
}
for(int i = 1 ; i <= q_ ; i++) {
int tmp = 1;
tmp = gcd(ans[i][0] , ans[i][1]);
printf("%lld/%lld\n" , ans[i][0] / tmp , ans[i][1] / tmp);
}
return 0;
}
暴力
未用unsigned int
处理
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define nn 100010
using namespace std;
int read() {
int re = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0',
c = getchar();
return re;
}
int gcd(int a , int b) {
return b == 0 ? a : gcd(b , a % b);
}
int vis[nn];
int a[nn];
int n , q;
int main() {
n = read(), q = read();
for(int i = 1 ; i <= n ; i++)
a[i] = read();
for(int i = 1 ; i <= q ; i++) {
memset(vis , 0 , sizeof(vis));
int l = read() , r = read();
if(l == r) {
puts("0/1");
continue;
}
for(int j = l ; j <= r ; j++)
vis[a[j]]++;
int cnt = 0;
for(int j = 1 ; j <= n ; j++)
if(vis[j] != 0)
cnt += vis[j] * (vis[j] - 1) / 2;
int tmp = (r - l) * (r - l + 1) / 2;
printf("%d/%d\n" , cnt / gcd(cnt , tmp) , tmp / gcd(cnt , tmp));
}
return 0;
}
数据生成
#include <bits/stdc++.h>
using namespace std;
int random(int r , int l = 1) {
return r == l ? l : (long long) rand() * rand() % (r - l) + l;
}
int main() {
srand((unsigned)time(0));
int n = random(10000);
int q = random(10000);
printf("%d %d\n" , n , q);
for(int i = 1 ; i <= n ; i++)
printf("%d " , random(n));
putchar('\n');
for(int i = 1 ; i <= q ; i++) {
int l = random(n) , r = random(n);
if(l > r)swap(l , r);
printf("%d %d\n" , l , r);
}
return 0;
}