初次接触分块思想

2024-03-27 22:58
文章标签 思想 接触 分块 初次

本文主要是介绍初次接触分块思想,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在练习mobius反演的时候有一题需要用分块的思想来优化,于是第一次听说了分块思想。比较有名的当属号称可以解决所有不修改、离线查询问题的莫队算法。几乎所有的莫队算法的介绍都和[BZOJ]2038 小Z的袜子有关,相关大神博客:http://www.cnblogs.com/kuangbin/p/3263483.html
先来个稍简单的分块题:


codeforces 86 D. Powerful array

http://codeforces.com/problemset/problem/86/D
大意:给定一串数字,给定一系列询问,问在相应区间内 Ks·Ks·s     的和,其中Ks是K数字S在区间内出现的次数。
分块解决,相关证明:

Let's sort the query intervals according to the following rule: first come the intervals with the left ends in Q_1, then the intervals with the left ends in Q_2, and so on. And if the left ends of the two queries belong to the same part, then the interval with the more left right end is assumed to be smaller.
In order to prove the stated asymptotic behavior we will follow the steps of the left and the right ends independently. We note that the left ends that belong to the same Q_i make <= n / p steps, and transition to Q_{i+1} costs no more than 2 * n / p steps. Therefore the left ends make <= n/p * n + 2*n steps (the second summand is O(n), and it's negligible).
The right ends in the common group move only to the right, and this proves <= n * p steps (during the whole process) estimate. We will estimate the transition to the next Q_i at no more than n steps, so overall we get < = 2 * n * p steps.
Thus, the total number of steps is no more than (n / p * n + 2 * n * p). Now we choose p = sqrt(n) which proves the statement.

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int N=2e5+10,M=1e6+10;
int a[N],cnt[M];
struct node{int x,y,l,dex;
}edge[N];
int cmp(node a,node b){return a.l<b.l||(a.l==b.l&&a.y<b.y) ;
}
LL ans,res[N];
int L,R;
void query(int x,int y,int dex){if(dex){for(int i=L;i<x;i++){cnt[a[i]]--;ans=ans-((cnt[a[i]]<<1)+1)*a[i];}for(int i=x;i<L;i++){ans=ans+((cnt[a[i]]<<1)+1)*a[i];cnt[a[i]]++;}for(int i=R+1;i<=y;i++){ans=ans+((cnt[a[i]]<<1)+1)*a[i];cnt[a[i]]++;}for(int i=y+1;i<=R;i++){cnt[a[i]]--;ans=ans-((cnt[a[i]]<<1)+1)*a[i];}}else {for(int i=x;i<=y;i++) {ans=ans+((cnt[a[i]]<<1)+1)*a[i];cnt[a[i]]++;}}L=x;  R=y;
}
int main()
{//freopen("cin.txt","r",stdin);int n,t;while(cin>>n>>t){int len=sqrt(1.0*n);memset(cnt,0,sizeof(cnt));for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=0;i<t;i++){scanf("%d%d",&edge[i].x,&edge[i].y);edge[i].dex=i;edge[i].l=(edge[i].x-1)/len;}sort(edge,edge+t,cmp);ans=0;for(int i=0;i<t;i++){query(edge[i].x,edge[i].y,i);res[edge[i].dex]=ans;}for(int i=0;i<t;i++){printf("%I64d\n",res[i]);}}return 0;
}

这是那道和mobius相关的题:

spoj  PGCD - Primes in GCD Table(mobius+分块)
http://www.spoj.com/problems/PGCD/en/
大意: 在一张(a,b)的表格中,填写完整对应交点值gcd(i,j)。问填写了多少次的素数。
即求解最大公约数是素数的组合有多少个。
莫比乌斯反演:
其中d就是各种素数。求解

学习了大神的博文: http://blog.csdn.net/jayye1994/article/details/12621589
设 
那么最开始处理时,sum[i*pri[j]]+=sum[i];  再前缀和处理.
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int N=1e7+10;
int mu[N],pri[N/10],cnt=0;
bool vis[N];
LL sum[N];
void getmu(){mu[1]=1;for(int i=2;i<N;i++){if(!vis[i]){mu[i]=-1;pri[cnt++]=i;}for(int j=0;j<cnt&&pri[j]*i<N;j++){vis[i*pri[j]]=1;if(i%pri[j]==0){mu[i*pri[j]]=0;break;}else mu[i*pri[j]]=-mu[i];}}for(int i=1;i<N;i++){if(mu[i]){for(int j=0;i*pri[j]<N&&j<cnt;j++){sum[i*pri[j]]+=mu[i];}}}for(int i=1;i<N;i++){sum[i]+=sum[i-1]*1LL;}
}
int main()
{//freopen("cin.txt","r",stdin);int a,b,t;getmu();cin>>t;while(t--){scanf("%d%d",&a,&b);if(a>b){a=a^b;  b=a^b;  a=a^b;}LL ans=0;for(int i=1;i<=a;i++){  //10/4=2;  10/2=5;int t1=a/i,t2=b/i;int next=min(a/t1,b/t2);ans=ans+1LL*t1*t2*(sum[next]-sum[i-1]);i=next;}printf("%lld\n",ans);}return 0;
}




这篇关于初次接触分块思想的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853675

相关文章

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

实例demo理解面向接口思想

浅显的理解面向接口编程 Android开发的语言是java,至少目前是,所以理解面向接口的思想是有必要的。下面通过一个简单的例子来理解。具体的概括我也不知道怎么说。 例子: 现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘、MP3、移动硬盘等设备进行数据交换。已知要实现U盘、MP3播放器、移动硬盘三种移动存储设备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的

【Java编程思想】线程的基本协作机制 与 线程的中断

wait/notify Java在Object类中定义了一些线程协作的基本方法,wait和notify public final void wait() throws InterruptedException;public final native void wait(long timeout) throws InterruptedException; 一个带时间参数,单位是毫秒,表示最

【Java编程的思想】理解synchronized

用法和基本原理 synchronized可以用于修饰类的实例方法、静态方法和代码块 实例方法 在介绍并发基础知识的时候,有一部分是关于竞态条件的,当多个线程访问和操作同一个对象时,由于语句不是原子操作,所以得到了不正确的结果。这个地方就可以用synchronized进行处理 public class Counter {private int count;public synchroni

【ShuQiHere】从残差思想到 ResNet:深度学习的突破性创新

【ShuQiHere】引言 在深度学习的迅速发展中,卷积神经网络(CNN)凭借其在计算机视觉领域的出色表现,已经成为一种主流的神经网络架构。然而,随着网络层数的增加,研究人员逐渐发现了一个关键问题:梯度消失 😖 和 梯度爆炸 💥,这使得训练非常深的网络变得极其困难。为了解决这一问题,残差思想 💡 被提出,并在 2015 年由 Kaiming He 等人正式引入 ResNet 中。这一创新不

nosql之mongodb初接触(一)

官网下载地址:(https://www.mongodb.com/download-center?jmp=nav#community)作为一个nosql的产品,mongodb和redis可谓旗鼓相当.下载介绍一下在ubuntu16.04版本下mongodb的使用版本:mongndb3.2.7 百度下载 http://pan.baidu.com/s/1eSfnIZg 下载解压

最近刚接触用到的一些linux命令(CentOS7的命令)二〇一八年十月三十日

linux  查看本地     ip  ip addr  查看本地系统     #cat /etc/issue 在CentOS下执行显示为: CentOS release 5.7 (Final) Kernel \r on an \m 或在Ubuntu下显示为: Ubuntu 11.04 \n \l 可以用来查看当前正在运行的 Ubuntu 的版本号。  查看系统内核     uname -a

初次用用Spring 和mybatis整合的报出Manual close is not allowed over a Spring managed SqlSession错误

一般这种错误是由于没有删dao实现类中的close,因为框架已经帮你写好了

Spring Boot实现大文件分块上传

1.分块上传使用场景 大文件加速上传:当文件大小超过100MB时,使用分片上传可实现并行上传多个Part以加快上传速度。 网络环境较差:网络环境较差时,建议使用分片上传。当出现上传失败的时候,您仅需重传失败的Part。 文件大小不确定: 可以在需要上传的文件大小还不确定的情况下开始上传,这种场景在视频监控等行业应用中比较常见。 2.实现原理 实现原理其实很简单,核心就是客户端把大文件