小Z的袜子 莫队算法模板

题解:
这道题是莫队算法入门题之一,根据组合公式和每次都是只拿2个可知Cn2那么我们化简可以得到Cn2=n*(n-1)/2,那么我们可以在每次修改的时候减去之前的影响,再加上现在的影响就可以得到答案了,具体怎么写,看我代码吧,还有就是这道题要开LL,不然会教你做人。。。
题外话:
这道题别人轻易就过了,而我跳了很多坑。。。因为自己有点懒所以在关于l分块的写法上跟网上的有点不同,导致不断的出错, 后面经过不断的修改终于写出了AC的绿色了,让我很高兴,也学会了别人如何优秀的分块,而不是我之前那种有点挫的分块。。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define LL long long int
using namespace std;
const int MAXN=50000+7;
struct node
{
    int l,r;
    int id;
    int pos;
}q[MAXN];
bool cmp(node c,node d)
{
    if(c.pos==d.pos) return c.r<d.r;//同一个块时以r排序 
    return c.l<d.l;//不同块时以l排序 
}
struct node2
{
    LL x,y;
}ans[MAXN];
int a[MAXN],block[MAXN];
LL cnt[MAXN];
LL val;
LL gcd(LL x,LL y) { return x%y ? gcd(y, x%y) : y; }  
void add(int x)
{
    val-=cnt[a[x]]*(cnt[a[x]]-1);   
    cnt[a[x]]++;
    val+=cnt[a[x]]*(cnt[a[x]]-1);
}
void del(int x)
{
    val-=cnt[a[x]]*(cnt[a[x]]-1);   
    cnt[a[x]]--;
    val+=cnt[a[x]]*(cnt[a[x]]-1);
}
int main()
{
//  freopen("a.txt","r",stdin); 
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        memset(cnt,0,sizeof(cnt));
        int s=sqrt(n);      
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),block[i]=(i-1)/s+1;//如果写成i/s的话1-9就会出现,1,2为一块,3,4,5为一块,6,7,8为一块,而9为一块 
        for(int i=1;i<=m;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i,q[i].pos=block[q[i].l];//这里的q[i].pos也可以写成q[i]=pos=q[i].l/ssort(q+1,q+m+1,cmp);
//      for(int i=1;i<=m;i++)
//      printf("%d %d  %d\n",q[i].l,q[i].r,q[i].pos);
        memset(cnt,0,sizeof(cnt));
        int l=1,r=0;
        val=0;
        for(int i=1;i<=m;i++)
        {
        //      printf("%d\n",i);
//          if(q[i].l==q[i].r)
//          {
//              ans[q[i].id].x=0,ans[q[i].id].y=1;
//              continue;
//          }
            while(l<q[i].l)
            {
                del(l);
                l++;
            }
            while(l>q[i].l)
            {
                l--;
                add(l);
            }
            while(r<q[i].r)
            {
                r++;
                add(r);
            }
            while(r>q[i].r)
            {
                del(r);
                r--;
            }
            LL temp=(LL)(q[i].r-q[i].l+1)*(q[i].r-q[i].l);//MD,这里忘记转化成LL被教做人,导致我找了一晚上,不断的WA,不断的怀疑人生,哎什么时候能改掉这个坏毛病 
            LL w=val;
            LL g=gcd(w,temp);
            temp/=g;
            w/=g;
            ans[q[i].id].x=w,ans[q[i].id].y=temp;
        }
        for(int i=1;i<=m;i++)
        printf("%lld/%lld\n",ans[i].x,ans[i].y);
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值