P1494 [国家集训队]小Z的袜子

目录

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;
}
上一篇:数据库 ----- 实验二:SQL的数据定义和数据更新


下一篇:莫队