小z的袜子

题目原址

对于L,R的询问。

设其中颜色为x,y,z..........的袜子的个数为a,b,c.......

那么答案即为 (a*(a-1)/2+b*(b-1)/2+c*(c-1)/2....)/((R-L+1)*(R-L)/2)(a∗(a−1)/2+b∗(b−1)/2+c∗(c−1)/2....)/((R−L+1)∗(R−L)/2)

化简得: (a^2+b^2+c^2+...x^2-(a+b+c+d+.....))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(a+b+c+d+.....))/((R−L+1)∗(R−L))

即: (a^2+b^2+c^2+...x^2-(R-L+1))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(R−L+1))/((R−L+1)∗(R−L))

我们需要解决的一个问题

求一个区间内每种颜色数目的平方和。

使用莫队的相关知识

#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define ll long long int
#define maxn 50010
ll n,m,vis[maxn],a[maxn];
ll num[maxn],ans=0,l,r;
typedef struct nodee{
    int l,r,id;
    ll a,b;
}node;
node maze[maxn];
ll gcd(ll a,ll b)
{
    if(a%b==0)
        return b;
    return gcd(b,a%b);
}
bool cmp(node a,node b)
{
    if(vis[a.l]==vis[b.l])
        return a.r<b.r;
    return a.l<b.l;
}
bool cmpp(node a,node b)
{
    return a.id<b.id;
}
void pls(int x)
{
    ans-=num[a[x]]*num[a[x]];
    num[a[x]]+=1;
    ans+=num[a[x]]*num[a[x]];
}
void min(int x)
{
    ans-=num[a[x]]*num[a[x]];
    num[a[x]]-=1;
    ans+=num[a[x]]*num[a[x]];
}
int main()
{
    cin>> n >> m;
    for(int i=1;i<=n;i++)
        cin >> a[i];
    ll temp=(ll)sqrt((double)n);
    
    memset(num,0,sizeof(num));
    memset(vis,0,sizeof(vis));
    
    for(int i=1;i<=n;i++)
        vis[i]=(i-1)/temp+1;
    for(int i=1;i<=m;i++)
    {
        cin >> maze[i].l >> maze[i].r;
        maze[i].id=i;
    }
    sort(maze+1,maze+m+1,cmp);
    l=1;
    r=0;
    ans=0;
    
    for(int i=1;i<=m;i++){
    	while(r<maze[i].r){
    		r++;
    		pls(r);
        }
        while(r>maze[i].r){
            min(r);
            r--;
        }
        while(l<maze[i].l){
            min(l);
            l++;
        }
        while(l>maze[i].l){
            l--;
            pls(l);
        }
        
        if(maze[i].l==maze[i].r)
        {
            maze[i].a=0;
            maze[i].b=1;
            continue;
        }
        
        maze[i].a=ans-(maze[i].r-maze[i].l+1);
        maze[i].b=(maze[i].r-maze[i].l+1)*1LL*(maze[i].r-maze[i].l);
        ll gcdd=gcd(maze[i].a,maze[i].b);
        maze[i].a/=gcdd;
        maze[i].b/=gcdd;
    }
    
    sort(maze+1,maze+m+1,cmpp);
    
    for(int i=1;i<=m;i++)
        cout << maze[i].a << '/' << maze[i].b << endl;
        
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值