声明


数字对

Time Limits: 2000 ms    Memory Limits: 262144 KB

Description

    小 H 是个善于思考的学生,现在她又在思考一个有关序列的问题。 
    她的面前浮现出一个长度为 n 的序列 {ai},她想找出一段区间 [L, R] (1 <= L <= R <= n)。
    这个特殊区间满足,存在一个 k (L <= k <= R),并且对于任意的 i (L <= i <= R),ai 都能被 ak 整除。这样的一个特殊区间 [L, R] 价值为 R - L。
    小H想知道序列中所有特殊区间的 最大价值 是多少,而有多少个这样的区间呢?这些区间又分别是哪些呢?你能帮助她吧。
 

Input

    第一行,一个整数 n.
    第二行,n 个整数,代表 ai.
 

Output

    第一行两个整数,num 和 val,表示价值最大的特殊区间的个数以及最大价值。
    第二行 num 个整数,按升序输出每个价值最大的特殊区间的 L.
 

 
 
  Sample Input
 
    输入1:
     5
     4  6  9  3  6
 
    输入2:
     5
     2  3  5  7  11
 

 
  Sample Output
    
    输出1:
     1  3
     2
 
    输出2:
     5  0
     1  2  3  4  5
 

Data Constraint

    30%: 1 <= n <= 30 , 1 <= ai <= 32.
    60%: 1 <= n <= 3000 , 1 <= ai <= 1024.
    80%: 1 <= n <= 300000 , 1 <= ai <= 1048576.
    100%: 1 <= n <= 500000 , 1 <= ai < 2 ^ 31.
 
 

 

    最近发现有用暴力等水法A掉这题的,如从头到尾枚举 ak ,然后再向两边搜索的水法。

  然而如果所有的 ai 都相同的话,时间复杂度就为O(n2),完全过不了。

  如:

  500000

  后面 500000 个 1

  此时时间复杂度为O(5000002),不知道运行到猴年马月,直接卡掉水法。

 

  接下来看正解(可能有其他更简单的方法,但这种方法绝对不会被卡掉!): 二分+rmq+hash

 

 
  分析:
    
    看到了最大价值,即求最优解,脑海中立马想到了:贪心、dp、优化的搜索(或暴力)和 二分答案 。显然,此题是在序列中操作,数据范围大,贪心条件不满足,明显的二分答案!!!
    于是用二分答案求出序列的最大长度,但如何判断答案 mid 的可行性和计算序列个数与开头位置呢?
 
    这样,问题就转化成如何判断某个区间是否存在:对于任意的 i (L <= i <= R),ai 都能被 ak 整除 了。
    显然,搜索是最普遍的选择,那这里我就讲讲搜索的优化方案:
 
    或许你们会问:不仅要询问每个区间(O(n)),又要找出其中有没有 ak 存在(O( n2)),时间复杂度不是 n吗,怎么过???
 

 
  优化方案:
  
    优化一:
 
      对于任意的 i (L <= i <= R),ai 都能被 ak 整除 中的 ak,是很好求出来的,就是区间几个数的最大公约数(gcd),在询问前预处理一下,线上调用即可。
      但是,对于一般的预处理(除前缀和和其他玄学预处理外),复杂度都是O(n2)的,一样过不了(哭笑不得~)。。。
 
      但是,在序列的维护中,自然想到 线段树、树状数组、rmq 啦~(对于前两项此题应该也能维护 gcd 吧?!~)
      我们了解过的 rmq 都是维护最大最小值的,以其速度快,范围广而出名。此题,一样可以维护区间的 gcd
 
      举个栗子:  4  6  9
      若已求出前两个数的 gcd 为2(rmq[1,1]=2),后一个数的 gcd 为 9(rmq[3,0]=a[3]=9),那区间的 gcd 就是 gcd(2,9)=1 啦~
 
      预处理时间复杂度降到 O(n log2 n)啦,在搜索时直接 O(1)的复杂度就能算出区间最小公约数(和 rmq 求最大最小值一样的,换成 gcd 了而已)。
 
    优化二:
      
      通过优化一算出区间的 ak 后,我们就要开始找区间内有没有这个 ak 了~
 
      然而我们发现,每个区间的搜索 O(n)不可省,而找 ak 又要 O(n),那岂不是 O(n2)吗(虽然达不到,但也接近了,加上预处理和二分答案等,绝对过不了)
      于是进一步优化:
 
      毕竟我们只找一个数 ak,很容易想到出现一个数就在 flag 数组打个标记,找有没有 ak 时直接判断 flag[ak] 是否打过标记就行了。
      而区间的移动一次的话,就 O(1)把新的那个数打一个标记,把出区间的那个删掉标记即可~
 
      此过程时间复杂度将至 O(1),效率极高,是在某个区间搜某些数时的常用方法,可以经常拿来用。
 
    优化三:
      光有优化二是不行的,因为它用空间换时间,会 MLE 的。(毕竟 ak 可达 20 多亿,数组开得了那么多吗???)
      所以,在用了优化二后,常常用这种方法解决空间问题:哈希表~(它俩基本绑定了,哈希是利用无用的空间存有用的数。不会的自己学,不必多说)
 
      但是,这里的哈希有三种模式: 1. 查询某数在哈希表中的位置(用于删标记);  2. 把某数存进哈希表(用于打标记);  3. 查询某数是否存在(用于查询区间内是否有 ak)。
 
      于是,我们用哈希表的稀少时间换了大量的空间~~~
      

 
  所以总体说,预处理 O(n log2 n),二分 O(log2 n*check),在 check 中,区间询问 O(n),找 ak O(hash)(hash 是哈希的时间复杂度,常数级别)
 
  这样,我们就把 O(n3)的时间复杂度将至 O(n log2 n+n log2 n*hash),粗略说就是 O(n log2 n),只是有点常数而已,不用卡常都能过(毕竟 2 秒时限)~~~
  
  下附标程,我就不写注释了~
    

 uses math;
const
mo=;
var
l,r,mid,i,n,j,t,cnt:longint;
a,b,h,ans:array[..] of longint;
rmq:array[..,..] of longint;
function gcd(x,y:longint):longint;
begin
if y= then exit(x) else exit(gcd(y,x mod y));
end;
function hash(x,mode:longint):boolean;
var
k:longint;
begin
k:=x mod mo;
while (h[k]<>) and (h[k]<>x) do
begin
inc(k);
if k>mo then k:=;
end;
if mode= then cnt:=k else
if mode= then h[k]:=x else
if h[k]=x then exit(true) else exit(false);
end;
function check(x:longint):boolean;
var
l,t,j,flag,r:longint;
begin
fillchar(h,sizeof(h),);
for i:= to x do
hash(a[i],);
flag:=;
for l:= to n-x+ do
begin
hash(a[l-],);
h[cnt]:=;
r:=l+x-;
hash(a[r],);
t:=trunc(ln(r-l+)/ln());
j:=gcd(rmq[l,t],rmq[r-(<<t)+,t]);
if hash(j,) then
begin
flag:=;
inc(ans[x]);
b[ans[x]]:=l;
end;
end;
if flag= then exit(false) else exit(true);
end;
begin
readln(n);
for i:= to n do
begin
read(a[i]);
rmq[i,]:=a[i];
end;
readln;
t:=trunc(ln(n)/ln())+;
for j:= to t do
for i:= to n do
if i+(<<j)-<=n then
rmq[i,j]:=gcd(rmq[i,j-],rmq[i+(<<(j-)),j-]);
l:=; // l,r,mid 存的是区间长度
r:=n;
while l<r do
begin
mid:=(l+r) div +;
if check(mid) then l:=mid else r:=mid-;
end;
if ans[l]= then
begin
writeln(n,'');
for i:= to n- do
write(i,' ');
writeln(n);
halt;
end;
writeln(ans[l],' ',l-); //要输出价值,就是长度-
for i:= to ans[l]- do
write(b[i],' ');
writeln(b[ans[l]]);
end.

标程

 

纪中OJ 2019.01.25【NOIP提高组】模拟 B 组 T2 数字对的更多相关文章

  1. 纪中OJ 2019.02.15【NOIP提高组】模拟 B 组 梦回三国 比赛题解(第一个)

    声明 旁边的同学小 H(胡)对我说: “哟,比赛拿了 140,强!要知道,如果哥第三题 AC 了,哥就 230 了,你个废柴!!!(比赛实际分数 130 额呵)” 顿时,千万草泥马从我心中奔腾而过:你 ...

  2. 【纪中集训】2019.08.01【NOIP提高组】模拟 A 组TJ

    T1 Description 给定一个\(N*N(N≤8)\)的矩阵,每一格有一个0~5的颜色.每次可将左上角的格子所在连通块变为一种颜色,求最少操作数. Solution IDA*=启发式迭代加深 ...

  3. IntelliJ IDEA 2018.3.3配置 Tomcat 9,控制台出现中文乱码 “淇℃伅”(2019/01/25)

    (win10系统) 全新idea配置全新版本Tomcat突遇 “淇℃伅”,网上大部分解决方案均已失效 似乎是idea与Tomcat命令行输出格式不一致所致,千辛万苦在某一小角落发现这个方法,一针见血, ...

  4. 【纪中集训2019.3.27】【集训队互测2018】小A的旅行(白)

    题目 描述 ​ \(0-n-1\)的图,满足\(n\)是\(2\)的整数次幂, $ i \to j $ 有 $ A_{i,j} $ 条路径: ​ 一条路径的愉悦值定义为起点和终点编号的\(and\)值 ...

  5. 【纪中集训2019.3.23】Deadline

    题意 描述 一个二分图\((A,B)\),每个点额外有一个颜色0或者1: 匹配时,只能相同颜色的点匹配: 给出\(A\)中的颜色,问如何分配\(B\)种的颜色使得\((A,B)\)的最大匹配最小: 范 ...

  6. 【纪中集训2019.3.12】Z的礼物

    题意 已知\(a_{i} = \sum_{j=1}^{i} \{^{i} _{j} \}b_{j}\), 给出\(a_{1} 到 a_{n}\) : 求\(b_{l} 到 b_{r}\)在\(1e9+ ...

  7. 【纪中集训2019.3.12】Mas的仙人掌

    题意: ​ 给出一棵\(n\)个点的树,需要加\(m\)条边,每条边脱落的概率为\(p_{i}\) ,求加入的边在最后形成图中仅在一个简单环上的边数的期望: \(1 \le n \ , m \le 1 ...

  8. 【2019.7.25 NOIP模拟赛 T3】树(tree)(dfs序列上开线段树)

    没有换根操作 考虑如果没有换根操作,我们该怎么做. 我们可以求出原树的\(dfs\)序列,然后开线段树维护. 对于修改操作,我们可以倍增求\(LCA\),然后在线段树上修改子树内的值. 对于询问操作, ...

  9. 【2019.7.25 NOIP模拟赛 T1】变换(change)(思维+大分类讨论)

    几个性质 我们通过推式子可以发现: \[B⇒AC⇒AAB⇒AAAC⇒C\] \[C⇒AB⇒AAC⇒AAAB⇒B\] 也就是说: 性质一: \(B,C\)可以相互转换. 则我们再次推式子可以发现: \[ ...

随机推荐

  1. December 31st 2016 Week 53rd Saturday

    In every triumph, there's a lot of try. 每个胜利背后都有许多尝试. This Year is over, and let it be. It would be ...

  2. jq模仿h5 placeholder效果

    $(".pay-license input").on("input propertychange blur",function(){ if($(this).va ...

  3. 关于Mysql查询varchar类型错误问题

    因为后台所有表ID都是按照雪花算法生成的18位数字,需要对接到Android,Ios和H5,此时H5会出现字符超长溢出,所以直接把ID改为varchar类型. 如我的一张表ID为varchar(18) ...

  4. BZOJ5072:[Lydsy1710月赛]小A的树(树形DP)

    Description BZOJ只是扔了个下载链接 Solution 设$f[x][i]$表示$x$点选中$i$个黑点的最小连通块. 设$g[x][i]$表示$x$点选中$i$个黑点的最大连通块. 转 ...

  5. 2763. [JLOI2011]飞行路线【分层图最短路】

    Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并 ...

  6. nordic对苹果性能测试

    环境: app采用nrf connect或lightblue均可: nordic从端采用nrf52840开发板pca10056: 说明与规定: (1)鉴于手机app无法主动连续快速发送多包数据,故只测 ...

  7. Oracle输出数字1-10

    ,) from dual connect by level<

  8. Java中如何判断一个字符串是否为数字

    方法一:异常处理 public static boolean isInteger(String str){ try { Integer i = Integer.parseInt(str); retur ...

  9. Python 学习笔记(十五)Python类拓展(二)方法

    方法 绑定方法和非绑定方法 绑定方法和非绑定方法在创建时没有任何区别,同一方法,既可以为绑定方法,也可以为非绑定方法,一切不同都只在调用时的手法上有所区别. 绑定方法即该方法绑定类的一个实例上,必须将 ...

  10. I、Python 环境搭建

    I.安装Python https://www.python.org/downloads/windows/ 下载路径总是变,认准那个名字 安装, 记住,所有语言都推荐安装在 默认路径,不要相信那些让你改 ...