• 数据结构:莫队


    莫队算法是用来处理一类无修改的离线区间询问问题

    莫队的精髓就在于,离线得到了一堆需要处理的区间后,合理的安排这些区间计算的次序以得到一个较优的复杂度

    代表题目是BZOJ2038这道题

     进行区间询问[l,r],输出该区间内随机抽两次抽到相同颜色袜子的概率

    分母就是n*n(表示两两袜子之间的随机组合),分子是一个累加和,累加的内容是该区间内每种颜色i出现次数sum[i]的平方

    只需要用莫队处理每个区间内不同数字的平方和就好了

    如果我们已知[l,r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l,r-1]的答案,即可使用莫队算法

    如果已知[l,r]的答案,要求[l’,r’]的答案,我们很容易通过|l – l’|+|r – r’|次转移内求得

    将n个数分成sqrt(n)块

    按区间排序,以左端点所在块内为第一关键字,右端点为第二关键字,进行排序

    排序之后直接暴力就可以了

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=50005;
     6 int n,m;
     7 int pos[maxn],c[maxn];
     8 long long ans;
     9 long long s[maxn];
    10 struct Data
    11 {
    12     int l,r,id;
    13     long long a,b;
    14 }a[maxn];
    15 long long gcd(long long a,long long b)
    16 {
    17     return b==0?a:gcd(b,a%b);
    18 }
    19 bool cmp(Data a,Data b)
    20 {
    21     if(pos[a.l]==pos[b.l]) return a.r<b.r;
    22     return a.l<b.l;
    23 }
    24 bool cmp_id(Data a,Data b)
    25 {
    26     return a.id<b.id;
    27 }
    28 void update(int p,int add)
    29 {
    30     ans-=s[c[p]]*s[c[p]];
    31     s[c[p]]+=add;
    32     ans+=s[c[p]]*s[c[p]];
    33 }
    34 void solve()
    35 {
    36     for(int i=1,l=1,r=0;i<=m;i++)
    37     {
    38         for(;r<a[i].r;r++) update(r+1,1);
    39         for(;r>a[i].r;r--) update(r,-1);
    40         for(;l<a[i].l;l++) update(l,-1);
    41         for(;l>a[i].l;l--) update(l-1,1);
    42         if(a[i].l==a[i].r)
    43         {
    44             a[i].a=0;a[i].b=1;
    45             continue;
    46         }
    47         a[i].a=ans-(a[i].r-a[i].l+1);
    48         a[i].b=(long long)(a[i].r-a[i].l+1)*(a[i].r-a[i].l);
    49         long long k=gcd(a[i].a,a[i].b);
    50         a[i].a/=k;a[i].b/=k;
    51     }
    52 }
    53 int main()
    54 {
    55     scanf("%d%d",&n,&m);
    56     for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    57     int block=int(sqrt(n));
    58     for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
    59     for(int i=1;i<=m;i++)
    60     {
    61         scanf("%d%d",&a[i].l,&a[i].r);
    62         a[i].id=i;
    63     }
    64     sort(a+1,a+m+1,cmp);
    65     solve();
    66     sort(a+1,a+m+1,cmp_id);
    67     for(int i=1;i<=m;i++)
    68         printf("%lld/%lld
    ",a[i].a,a[i].b);
    69     return 0;
    70 }
  • 相关阅读:
    HDU 1004 Let the Balloon Rise【STL<map>】
    UVA 1030
    UVA 10881
    POJ 3154 Graveyard【多解,数论,贪心】
    浅谈Notepad++选中行操作+快捷键+使用技巧【超详解】
    COGS 68. [NOIP2005] 采药【01背包复习】
    [phomeflashpic]怎样调用帝国CMS图片幻灯效果
    微信认证新增公对公账户银行卡转账支付审核费用 缩减认证审核时长
    微信公众平台回复过了怎么不能再次回复?亲们要注意查看"公众平台回复用户消息时限变更通知"的公告啊
    新版微信终于支持消息撤回了 微信零钱也能转账了[微信5.3.1.16更新]
  • 原文地址:https://www.cnblogs.com/aininot260/p/9524763.html
Copyright © 2020-2023  润新知