首页 > 其他分享 >C116 莫队二次离线 P4887 莫队二次离线

C116 莫队二次离线 P4887 莫队二次离线

时间:2024-04-15 22:24:01浏览次数:29  
标签:二次 int 离线 long ans include 莫队

视频链接:

 

 

 

 

 

Luogu P4887 【模板】莫队二次离线(第十四分块(前体))

// 莫队二次离线 O(n*sqrt(n)+n*C(k,14))
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;

const int N=100005;
int n,m,k,B,block[N],a[N],t[N],pre[N];
long long ans[N];
vector<int> b;  //二进制中1的个数为k的数
struct F{
  int id,l,r,z;
};
vector<F> f[N]; //待求贡献的信息
struct Q{
  int id,l,r;
  long long ans;
  bool operator<(Q &x){
    if(block[l]!=block[x.l])return l<x.l;
    return r<x.r;
  }
}q[N];

int count(int x){ //x的二进制中1的个数
  int s=0;
  while(x) s+=x&1,x>>=1;
  return s;
}
int main(){
  scanf("%d%d%d",&n,&m,&k); B=sqrt(n);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i),block[i]=(i-1)/B+1;
  for(int i=1,l,r;i<=m;i++)
    scanf("%d%d",&l,&r),q[i]={i,l,r};
  sort(q+1,q+m+1);
  for(int i=0;i<1<<14;++i)
    if(count(i)==k)b.push_back(i); //最多C(7,14)=3432
  for(int i=1;i<=n;i++){
    pre[i]=t[a[i]];//a1~a[i-1]与ai异或有k个1的数的个数
    for(auto x:b) ++t[a[i]^x];
  }
  for(int i=1,l=1,r=0;i<=m;i++){ //莫队
    //r右移:f(l,x-1)=f(1,x-1)-f(1,l-1), x~[r+1,qr]
    if(r<q[i].r) f[l-1].push_back({i,r+1,q[i].r,-1});
    while(r<q[i].r) q[i].ans+=pre[++r];
    //r左移:-f(l,x-1)=-(f(1,x-1)-f(1,l-1)), x~[qr+1,r]
    if(r>q[i].r) f[l-1].push_back({i,q[i].r+1,r,1});
    while(r>q[i].r) q[i].ans-=pre[r--];
    //l左移:f(x+1,r)=f(1,r)-f(1,x), x~[ql,l-1]
    if(l>q[i].l) f[r].push_back({i,q[i].l,l-1,1});
    while(l>q[i].l) q[i].ans-=pre[--l]+!k;
    //l右移:-f(x+1,r)=-(f(1,r)-f(1,x)), x~[l,ql-1]
    if(l<q[i].l) f[r].push_back({i,l,q[i].l-1,-1});
    while(l<q[i].l) q[i].ans+=pre[l++]+!k;
  }
  //二次离线,累计f(1,l-1)和f(1,r)的贡献
  memset(t,0,sizeof(t));
  for(int i=1,id,l,r,z;i<=n;i++){ //扫描ai
    for(auto& x:b) ++t[a[i]^x];   //与ai配对的数均+1
    for(auto& y:f[i]){            //以ai为边界的f
      for(int x=y.l;x<=y.r;x++)
        q[y.id].ans+=y.z*t[a[x]]; //累计配对贡献
    }
  }
  //后一个查询是前一个查询的增量,故求前缀和
  for(int i=2;i<=m;i++)q[i].ans+=q[i-1].ans;
  for(int i=1;i<=m;i++)ans[q[i].id]=q[i].ans;
  for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}

 

// 莫队二次离线 O(n*sqrt(n)+n*C(k,14))
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <tuple>
using namespace std;

const int N=100005;
int n,m,k,B,block[N],a[N],t[N],pre[N]; 
long long ans[N];
vector<int> b;   //二进制中1的个数为k的数
vector<tuple<int,int,int,int>> f[N]; //待求贡献的信息
struct Q{
  int id,l,r;
  long long ans;
  bool operator<(Q &x){
    if(block[l]!=block[x.l])return l<x.l;
    return r<x.r;
  }
}q[N];

int main(){
  scanf("%d%d%d",&n,&m,&k); B=sqrt(n);
  for(int i=1;i<=n;i++)
    scanf("%d",a+i),block[i]=(i-1)/B+1;
  for(int i=1,l,r;i<=m;i++)
    scanf("%d%d",&l,&r),q[i]={i,l,r};
  sort(q+1,q+m+1);
  for(int i=0;i<1<<14;++i) //b内最多C(7,14)=3432
    if(__builtin_popcount(i)==k)b.push_back(i); 
  for(int i=1;i<=n;i++){
    pre[i]=t[a[i]];//a1~a[i-1]与ai异或有k个1的数的个数
    for(auto x:b) ++t[a[i]^x];
  }
  
  for(int i=1,l=1,r=0;i<=m;i++){ //莫队
    //r右移:f(l,x-1)=f(1,x-1)-f(1,l-1), x~[r+1,qr]
    if(r<q[i].r) f[l-1].emplace_back(i,r+1,q[i].r,-1);
    while(r<q[i].r) q[i].ans+=pre[++r];
    //r左移:-f(l,x-1)=-(f(1,x-1)-f(1,l-1)), x~[qr+1,r]
    if(r>q[i].r) f[l-1].emplace_back(i,q[i].r+1,r,1);
    while(r>q[i].r) q[i].ans-=pre[r--];
    //l左移:f(x+1,r)=f(1,r)-f(1,x), x~[ql,l-1]
    if(l>q[i].l) f[r].emplace_back(i,q[i].l,l-1,1);
    while(l>q[i].l) q[i].ans-=pre[--l]+!k;
    //l右移:-f(x+1,r)=-(f(1,r)-f(1,x)), x~[l,ql-1]
    if(l<q[i].l) f[r].emplace_back(i,l,q[i].l-1,-1);
    while(l<q[i].l) q[i].ans+=pre[l++]+!k; 
  }
  //二次离线,累计f(1,l-1)和f(1,r)的贡献
  memset(t,0,sizeof(t));
  for(int i=1,id,l,r,z;i<=n;i++){ //扫描ai
    for(auto& x:b) ++t[a[i]^x];   //与ai配对的数均+1
    for(auto& y:f[i]){            //以ai为边界的f
      std::tie(id,l,r,z)=y;       //元组的赋值
      for(int x=l;x<=r;x++)       //累计配对贡献
        q[id].ans+=z*t[a[x]];
    }
  }
  //后一个查询是前一个查询的增量,故求前缀和
  for(int i=2;i<=m;i++)q[i].ans+=q[i-1].ans;
  for(int i=1;i<=m;i++)ans[q[i].id]=q[i].ans;
  for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}

 

P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P5501 [LnOI2019] 来者不拒,去者不追 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

 

标签:二次,int,离线,long,ans,include,莫队
From: https://www.cnblogs.com/dx123/p/18130171

相关文章

  • 莫队
    查询区间每个数出现的个数,离线算法,O(nsqrt(n))一、普通莫队题目链接https://www.luogu.com.cn/problem/P2709题目大意题目代码#include<iostream>#include<algorithm>#include<cmath>#definelllonglongconstintN=5e4+5;usingnamespacestd;intn,m,k,block......
  • 第二次实验
    练习一:line15是在1~65的范围内随机取数这个程序生成202383310001~202383310065之间的学号练习二:include<stdio.h>intmain(){charcolor;while(scanf("%c",&color)!=EOF){ switch(color){ case'r':printf("stop!\n"); break; case'g�......
  • Ubuntu下离线安装PostgreSQL
      首先,我的环境是Ubuntu20.04  如果是在线安装,根据官网的介绍很简单#安装包sudoaptupdatesudoaptinstallwgetgnupg#导入仓库sudosh-c'echo"debhttps://apt.postgresql.org/pub/repos/apt$(lsb_release-cs)-pgdgmain">/etc/apt/......
  • 莫队学习笔记
    目录普通莫队初遇——从暴力谈起困境——乱跑的指针优化——顺路而为之带修莫队参考资料普通莫队初遇——从暴力谈起我们通过一道例题来讨论普通莫队。题目链接。观察数据范围,一个很直接的想法是:开一个数组\(cnt\),\(cnt_i\)表示在询问的区间内数字\(i\)出现的次数。对于......
  • [离线技巧] 整体二分
    来介绍一下整体二分。整体二分需要满足一下条件:问题之间独立可以离线具有单调性答案贡献可合并我们通过几个例子,通俗的理解这个算法。问题\(1\)给定\(n\)个数,求第\(k\)小。我们思考这个问题怎么做。不用排序,显然,答案具有单调性。那么,我们可以二分一个答案,判断......
  • 农村高中生源转型期提升学生二次函数建模能力的课堂探究
      在新课程下,培养学生的数学核心素养是高中数学课堂教学的根本任务。其中的建模思想是数学核心素养培养的一个基本指标,是学生正确认识数学知识内在本质与原理的重要思维工具。通过在数学课堂教学中有效地应用建模思想,主要的应用意义体现在如下几个方面:其一,通过在数学课堂中融入......
  • 软工第二次任务-工作总结
    引言:在软件开发的广阔天地中,单元测试是确保代码质量和功能正确性的关键步骤。它不仅有助于及时发现和修复缺陷,还能提高开发效率,减少后期维护成本。本次任务旨在对软件工程中的单元测试进行全面的总结,以期为未来的开发工作提供宝贵的经验和参考。一、单元测试的重要性单元测试,顾......
  • #莫队二次离线,根号分治#洛谷 5398 [Ynoi2018] GOSICK
    题目\(m\)组询问求\(\sum_{l\leqi,j\leqr}[a_i\bmoda_j==0],n,m,a_i\leq5\times10^5\)分析设\(f(l,r,x)\)表示\(i或j\in[1,x],i或j\in[l,r]\)时的答案,\(g_x\)表示\([1,x]\)的答案,根号的做法可以通过三秒由于涉及区间内的求值,需要在莫队的基础上二次离线,那......
  • 从0到1的二次反序列化
    前言简单介绍下二次反序列化,顾名思义,就是反序列化两次,其主要意义是绕过黑名单的限制或不出网利用,有些CTF题把一大堆关键类全都ban了,这就让人无从下手,二次反序列化就是为此而生的SignedObject原理看构造函数,接受一个可序列化的对象,再进行一次序列化,简直不要太perfect关注一下......
  • P9750 [CSP-J 2023] 一元二次方程 题解
    题面。直接依照题意模拟即可,注意细节。细节第一注意输出分式时分母为\(1\)不输出,分子为\(0\)直接输出零且不带正负号。第二约分时,\(gcd\)内的两个数应该都是非负实数。第三可以单独输出符号,注意别有多余的符号。第四当方程有两根且均是有理数时,要根据\(2a\)的正......