题目

题目大意

首先有一个定义:

对于一个数,如果和它互质的数可以组成一个等差数列,那么这个数叫“好数”。

现在给你一个数列,有三种操作:

1、询问一段区间内的好数的个数。

2、将一段区间内的数分别模一个值。

3、将某个数修改。


思考历程

先看看这个题目。

好熟悉的题目啊!这不就是初中OJ上的某道数位DP的题吗?

然后发现不是那一道题,松了一口气。

一眼看下去,一定有什么数论。说不定在得到了什么结论之后,就变成一个非常简单的数据结构题了。

然后就在疯狂地推式子……最终没有推出来……

于是就弃疗了。


正解

经过打表找规律后,我们发现:

好数分为三种情况:

1、质数。

2、222的幂次。

3、666

随便想一想,我们很容易知道这些数都是好数。

可问题是,其它的数有没有可能是好数呢?

我不知道,我也不会证明……

不过对于这题来说,由于数据范围不大(也就是10610^6106以内),所以打个表当然是可以的……

这再次告诉了我们打表找规律很重要的道理。

在CGH大佬的讲解下,我终于会证明了……

首先,每个数都可以表示成2kx2^kx2kx的形式,其中xxx为奇数。

接下来我们分类讨论:

当x=1x=1x=1时

我觉得这个不用说……

当k=0k=0k=0时,

首先gcd(x−1,x)=1gcd(x-1,x)=1gcd(x−1,x)=1。

由于xxx为奇数,所以gcd(x−2,x)=1gcd(x-2,x)=1gcd(x−2,x)=1

那么x−1x-1x−1和x−2x-2x−2都与xxx互质,所以等差数列的公差为111。

既然这样,111到x−1x-1x−1都要和xxx互质。

所以xxx自然是质数。

当k>0k>0k>0时,

由于xxx为奇数,所以gcd(x−2,x)=1  gcd(x+2,x)=1gcd(x-2,x)=1 \ \ gcd(x+2,x)=1gcd(x−2,x)=1  gcd(x+2,x)=1

k&gt;0k&gt;0k>0且x&gt;1x&gt;1x>1所以x+2&lt;2kxx+2&lt;2^kxx+2<2kx

x−1x-1x−1和x+1x+1x+1为偶数,和2kx2^kx2kx不互质。显然xxx和2kx2^kx2kx也不互质。

所以公差为444。

首项显然是111,然后我们列出来:1 5 9...

111、555和2kx2^kx2kx互质,没有问题。

可是999呢?

如果2kx2^kx2kx和999互质,那么2kx2^kx2kx必定和333互质,所以不成立!

所以在k&gt;0k&gt;0k>0且x&gt;1x&gt;1x>1时,可以的取值范围在999以内。特别计算一下,只有666符合条件。

综上所述,只有000、222的幂次、质数、666可以为好数。

得证。

再次膜拜一下CGH大爷。

知道了这个结论之后,仔细地再想一想,其实出解还是很容易的。

首先,好数会和模有什么关系?不用想了,反正我们已经打出了表,对一下表,我们就知道它和模似乎没有什么关系。所以,我们考虑暴力。

暴力?不会爆炸吗?

我可以很肯定地告诉你,不会爆炸。

为什么?

有一个很显然的结论:当a&gt;ba&gt;ba>b时,amod&ThinSpace;&ThinSpace;b&lt;=a2a \mod b&lt;=\frac{a}{2}amodb<=2a​

可以感性理解,也可以理性证明:

我们可以分类讨论:

当a≥b&gt;a2a\geq b&gt;\frac{a}{2}a≥b>2a​时,那么amod&ThinSpace;&ThinSpace;b=a−b≤a2a\mod b =a-b\leq \frac{a}{2}amodb=a−b≤2a​

当b≤a2b\leq\frac{a}{2}b≤2a​时,那么amod&ThinSpace;&ThinSpace;b&lt;b≤a2a \mod b&lt;b\leq\frac{a}{2}amodb<b≤2a​

得证。

所以说,在每次操作中,某个数一定会缩小一半或以上。

在没有修改的情况下,xxx能取模lg⁡x\lg xlgx次(当然xxx大于模数)。

我们有一种很巧妙的思想,这种思想其实也不少见了。

有些操作看似暴力,实际上它的操作次数是有限的,所以你可以这么想:

不管操作次数有多少次,反正我最多只做这么多遍,你管我啊?

曾经我用过这个思想切掉了某一道题解说必须用块状链表,而不能用线段树的题目。我用了线段树AC,暴虐题解的感觉真爽……

对于这题,我们可以用线段树维护。

记录区间的好数个数还有最大值。

我们在操作2时,可以先看看这个区间的最大值是多少,如果最大值大于模数,那么就进入这个区间。

这样保证了进入每一个区间都不可能做无用功,所以保证了时间复杂度。

对于每个数,最多被模lg⁡106\lg 10^6lg106次,总共有nnn个数,每次暴力模一个数最多花费lg⁡n\lg nlgn的时间。所以说,不管怎样,你最多就暴力模了nlg⁡nlg⁡106n\lg n \lg 10^6nlgnlg106次。

实际上远远不到这么多,首先数据不会这么狠心地将所有数的价值榨干,其次,在进入一个区间后,处理一些去要处理的数往往是顺路的,也就是说,很难每次暴力下去模都花费lg⁡n\lg nlgn的时间。

可能你会问,修改怎么办?

修改就修改喽,管它呢!

你可以看做将原来的数删去,然后插入一个新的数。原来的数剩余被模的机会没了,新来的数还有一些被模的机会。然而,修改的次数也不多,是有范围的,级别也和nnn差不多吧。就当成是多了这么多个数,实际上时间复杂度也不会被影响。

然后呢,然后呢?当然是没有然后了。

这题就被轻轻松松地解决了。

代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100000
#define MAX 1000000
int n,m;
bool is[MAX+1];
int pri[MAX+1];
int sum[N*4+1],mx[N*4+1];
void build(int,int,int);
int qsum(int,int,int,int,int);
void find(int,int,int,int,int,int);
void change_set(int,int,int,int,int);
int main(){
memset(is,1,sizeof is);
//下面是求质数
for (int i=2;i<=MAX;++i){
if (is[i])
pri[++*pri]=i;
for (int j=1;i*pri[j]<=MAX && j<=*pri;++j){
is[i*pri[j]]=0;
if (i%pri[j]==0)
break;
}
}
//除了质数之外还有0,6,2^i
is[0]=1,is[6]=1;
for (int i=0;1<<i<=MAX;++i)
is[1<<i]=1;
scanf("%d%d",&n,&m);
build(1,1,n);
for (int i=1;i<=m;++i){
int op;
scanf("%d",&op);
if (op==1){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",qsum(1,1,n,l,r));
}
else if (op==2){
int l,r,mo;
scanf("%d%d%d",&l,&r,&mo);
find(1,1,n,l,r,mo);
}
else{
int x,y;
scanf("%d%d",&x,&y);
change_set(1,1,n,x,y);
}
}
return 0;
}
void build(int k,int l,int r){
if (l==r){
scanf("%d",&mx[k]);
sum[k]=is[mx[k]];
return;
}
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
sum[k]=sum[k<<1]+sum[k<<1|1];
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
int qsum(int k,int l,int r,int st,int en){
if (l==st && r==en)
return sum[k];
int mid=l+r>>1;
if (en<=mid)
return qsum(k<<1,l,mid,st,en);
if (mid<st)
return qsum(k<<1|1,mid+1,r,st,en);
return qsum(k<<1,l,mid,st,mid)+qsum(k<<1|1,mid+1,r,mid+1,en);
}
void find(int k,int l,int r,int st,int en,int mo){
if (mx[k]<mo)//如果没有可以被模的数,那就不要继续了
return;
if (l==r){
sum[k]=is[mx[k]%=mo];//暴力修改……
return;
}
int mid=l+r>>1;
if (en<=mid)
find(k<<1,l,mid,st,en,mo);
else if (mid<st)
find(k<<1|1,mid+1,r,st,en,mo);
else{
find(k<<1,l,mid,st,mid,mo);
find(k<<1|1,mid+1,r,mid+1,en,mo);
}
sum[k]=sum[k<<1]+sum[k<<1|1];
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}
void change_set(int k,int l,int r,int x,int c){
if (l==r){
sum[k]=is[mx[k]=c];
return;
}
int mid=l+r>>1;
if (x<=mid)
change_set(k<<1,l,mid,x,c);
else
change_set(k<<1|1,mid+1,r,x,c);
sum[k]=sum[k<<1]+sum[k<<1|1];
mx[k]=max(mx[k<<1],mx[k<<1|1]);
}

总结

首先,打表找规律是一样好东西。

在遇到什么看似是奇葩数论题的时候,如果推不出来,就打表找规律。

要知道有时候找规律比推式子简单多了。

还有,以后见到一些不怎么好维护的东西,就要联想到类似的方法。

如果操作是不可逆的东西,那就试着暴力搞。

反正怎么搞顶多这么多次,那就暴力呗!

JZOJ100045 【NOIP2017提高A组模拟7.13】好数的更多相关文章

  1. [JZOJ100043] 【NOIP2017提高A组模拟7.13】第K小数

    Description 有两个正整数数列,元素个数分别为N和M.从两个数列中分别任取一个数相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少. Input 输入文件包含三行. 第一行为 ...

  2. JZOJ 100029. 【NOIP2017提高A组模拟7.8】陪审团

    100029. [NOIP2017提高A组模拟7.8]陪审团 Time Limits: 1000 ms  Memory Limits: 131072 KB  Detailed Limits   Got ...

  3. JZOJ 5328. 【NOIP2017提高A组模拟8.22】世界线

    5328. [NOIP2017提高A组模拟8.22]世界线 (File IO): input:worldline.in output:worldline.out Time Limits: 1500 m ...

  4. JZOJ 5329. 【NOIP2017提高A组模拟8.22】时间机器

    5329. [NOIP2017提高A组模拟8.22]时间机器 (File IO): input:machine.in output:machine.out Time Limits: 2000 ms M ...

  5. JZOJ 5307. 【NOIP2017提高A组模拟8.18】偷窃 (Standard IO)

    5307. [NOIP2017提高A组模拟8.18]偷窃 (Standard IO) Time Limits: 1000 ms Memory Limits: 262144 KB Description ...

  6. JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)

    5286. [NOIP2017提高A组模拟8.16]花花的森林 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Descript ...

  7. JZOJ 5305. 【NOIP2017提高A组模拟8.18】C (Standard IO)

    5305. [NOIP2017提高A组模拟8.18]C (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Description ...

  8. 【NOIP2017提高A组模拟9.17】信仰是为了虚无之人

    [NOIP2017提高A组模拟9.17]信仰是为了虚无之人 Description Input Output Sample Input 3 3 0 1 1 7 1 1 6 1 3 2 Sample O ...

  9. 【NOIP2017提高A组模拟9.17】猫

    [NOIP2017提高A组模拟9.17]猫 题目 Description 信息组最近猫成灾了! 隔壁物理组也拿猫没办法. 信息组组长只好去请神刀手来帮他们消灭猫.信息组现在共有n 只猫(n 为正整数) ...

随机推荐

  1. scala中异常捕获与处理简单使用

    import java.io.IOException /** * 异常捕获与处理 */ object excepitonUse { def main(args: Array[String]): Uni ...

  2. Unity 手机屏幕适配

    ////如有侵权 请联系我进行删除 email:YZFHKM@163.com 1.游戏屏幕适配 屏幕适配是为了让我们的项目能够跑在各种电子设备上(手机,平板,电脑) 那么了解是适配之前首先要了解两个知 ...

  3. NOI2016

    luoguP1712 [NOI2016]区间 这是一道送分题. 对于我这种每天抄题解不动脑子思维僵化得厉害的智障选手就是送命题. 一直在想端点排序各种Treap搞... 正解: 已知一些区间,如何判断 ...

  4. 有关axios的request与response拦截

    // http request 拦截器 axios.interceptors.request.use( config => { var token = localStorage.getItem( ...

  5. [CTSC 2012]熟悉的文章

    二分+单调队列优化dp+后缀自动机 //CTSC2012 熟悉的文章 #include <bits/stdc++.h> using namespace std; const int max ...

  6. memcpy函数实现中的优化

    今天浏览Google面试题的时候,有看到一个memcpy的实现,以及如何去优化memcpy. 我对memcpy的实现的记忆就是,拷贝的时候需要从后往前拷贝,为何防止内存重叠. 但是如果去优化它我没有想 ...

  7. 实验室系统tomcat 6 java.lang.OutOfMemoryError: Java heap space

    java.lang.OutOfMemoryError: Java heap space

  8. Storm 测试

    本文将学习如何使用java创建Storm拓扑 Storm集群的组件 Storm集群类似于Hadoop集群,只不过 Hadoop 上运行"MapReduce jobs", Storm ...

  9. 面试系列八 es写入数据的工作原理

    (1)es写数据过程 1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点) 2)coordinating node,对document进行路由,将请求 ...

  10. printk函数速率限制

    如果你不小心, 你会发现自己用 printk 产生了上千条消息, 压倒了控制台并且, 可能地, 使系统日志文件溢出. 当使用一个慢速控制台设备(例如, 一个串口), 过量的消息速率也 能拖慢系统或者只 ...