zoukankan      html  css  js  c++  java
  • 【洛谷P1494】【BZOJ2038】小Z的袜子【莫队】

    题目大意:

    题目链接:
    洛谷:https://www.luogu.org/problemnew/show/P1494
    BZOJ:https://www.lydsy.com/JudgeOnline/problem.php?id=2038

    mm个询问,每次询问从[L,R][L,R]中选择两个元素相同的概率是多少。


    思路:

    • 莫队算法

    这道题是莫队的模板题。
    莫队算法其实是很简单的。码量也不算大。可以做到离线O(nn)O(nsqrt{n})处理一些区间问题。
    莫队的核心思想就是将询问排序,每次区间[l,r][l,r]的答案就从[l+1,r],[l1,r],[l,r+1],[l,r1][l+1,r],[l-1,r],[l,r+1],[l,r-1]转移来。
    反正我不会证明复杂度XDcolor{white} exttt{反正我不会证明复杂度XD}
    网上的讲解大部分都比较敷衍,这里就给出一篇比较好的讲解吧 链接


    代码:

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=50010;
    int n,m,T,l,r,a[N],pos[N];
    ll s[N],ans;
    
    struct Ask
    {
    	int l,r,id;
    	ll ans1,ans2;
    }ask[N];
    
    bool cmp1(Ask x,Ask y)
    {
    	if (pos[x.l]<pos[y.l]) return 1;
    	if (pos[x.l]>pos[y.l]) return 0;
    	return x.r<y.r;
    }
    
    bool cmp2(Ask x,Ask y)
    {
    	return x.id<y.id;
    }
    
    void add(int x) 
    {
    	ans-=s[a[x]]*(s[a[x]]-1)/2;
    	if (x) s[a[x]]++;
    	ans+=s[a[x]]*(s[a[x]]-1)/2;
    }
    
    void dev(int x)
    {
    	ans-=s[a[x]]*(s[a[x]]-1)/2;
    	if (x) s[a[x]]--;
    	ans+=s[a[x]]*(s[a[x]]-1)/2;
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	T=(int)sqrt(m);
    	if (m%T) T++;
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d",&ask[i].l,&ask[i].r);
    		ask[i].id=i;
    		pos[i]=(i-1)/T+1;
    	}
    	sort(ask+1,ask+1+m,cmp1);
    	for (int i=1;i<=m;i++)
    	{
    		for (;l<ask[i].l;l++) dev(l);
    		for (;l>ask[i].l;l--) add(l-1);
    		for (;r<ask[i].r;r++) add(r+1);
    		for (;r>ask[i].r;r--) dev(r);
    		if (l==r) ask[i].ans1=0,ask[i].ans2=1;
    		else
    		{
    			ll k=ask[i].r-ask[i].l+1;
    			ll a1=ans,a2=k*(k-1)/2;
    			ll GCD=__gcd(a1,a2);
    			ask[i].ans1=a1/GCD;
    			ask[i].ans2=a2/GCD;
    		}
    	}
    	sort(ask+1,ask+1+m,cmp2);
    	for (int i=1;i<=m;i++)
    		printf("%lld/%lld
    ",ask[i].ans1,ask[i].ans2);
    	return 0;
    }
    
  • 相关阅读:
    java中 == 与 equals
    java中只有值传递
    java中8种基本类型、包装类、常量池
    Markdown知识
    logback的使用和logback.xml详解[转]
    Log4J日志配置详解[转]
    批量删除Redis数据库中的Key
    linux的top命令参数详解
    Java之美[从菜鸟到高手演变]系列之博文阅读导航
    Java 密码扩展无限制权限策略文件[转]
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998187.html
Copyright © 2011-2022 走看看