P1494 [国家集训队]小Z的袜子
(洛谷没能交上去,就先放在博客里了)
这是个模板题
莫队的话,我学得别人,整了两个指针L和R
然后每个询问得话,就是让我们求:
从颜色相同的袜子里取两只的方案,然后再去除以这段从这段区间里随意取两只的方案
这怎么处理呢?当然可以用组合数直接求出来
而且,组合数只需要开C[N][3]就行,因为我们只需要穿两只袜子
我感觉还是挺好想的,但是我看题解里没人发,我就发一份
除了这个思路,其他基本都是模板,不会的话可以来我的博客
或者这个大佬的博客
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 5e4 + 5;
struct stu{
int l,r;
int id;
int block;
bool operator <(const stu &x) const {
if(x.block == block)
if(block % 2) return x.r < r;
else return x.r > r;
return x.block < block;
}
//莫队的普通排序,这样排更优
}q[N];
struct find_ans{
long long son;
long long mother;
}ans[N];
int l,r;
int n,m;
int v[N];
int a[N];
int cnt[N];
long long cur_ans;
long long C[N][4];
void init()//预处理组合数
{
for(int i = 0;i <= n;i ++) C[i][0] = 1;
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= 2;j ++)
C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
}
void add(int pos)
{
cnt[a[pos]] ++;
int x = cnt[a[pos]];
cur_ans = cur_ans + C[x][2] - C[x - 1][2];
}
void del(int pos)
{
cnt[a[pos]] --;
int x = cnt[a[pos]];
cur_ans = cur_ans + C[x][2] - C[x + 1][2];
}
long long gcd_(long long x,long long y)
{
if(!y) return x;
return gcd_(y,x % y);
}
find_ans ask()
{
long long this_ans,that_ans;
this_ans = C[r - l + 1][2];//总的方案数,分母
that_ans = cur_ans;
long long gcd = gcd_(this_ans,that_ans);
this_ans /= gcd;
that_ans /= gcd;
find_ans so_ans;
so_ans.son = that_ans;
so_ans.mother = this_ans;
if(!this_ans) so_ans.mother = 1;
return so_ans;
}
int main()
{
// freopen("8.in","r",stdin);
// freopen("88.out","w",stdout);
cin >> n >> m;
init();
for(int i = 1;i <= n;i ++) cin >> a[i];
int div = n / sqrt(m);
for(int i = 1;i <= m;i ++)
{
int x,y;
cin >> x >> y;
if(x > y) swap(x,y);//这个地方坑死了,数据居然有l > r
q[i].l = x;
q[i].r = y;
q[i].id = i;
q[i].block = x / div;
if(x == y)
{
ans[i].son = 0;
ans[i].mother = 1;
v[i] = 1;
continue;
}
}
sort(q + 1,q + 1 + m);
l = 1,r = 0;
for(int i = 1;i <= m;i ++)
{
if(v[q[i].id]) continue;
while(l < q[i].l) del(l ++);
while(l > q[i].l) add(-- l);
while(r < q[i].r) add(++ r);
while(r > q[i].r) del(r --);
ans[q[i].id] = ask();
}
for(int i = 1;i <= m;i ++)
cout << ans[i].son << "/" << ans[i].mother << endl;
return 0;
}