Luogu5629 【AFOI-19】区间与除法

9 篇文章 0 订阅
2 篇文章 0 订阅

原题链接:https://www.luogu.com.cn/problem/P5629

区间与除法

题目背景

SY 好不容易才解出QM给她的数学题,在恰午饭的时候,QM 向她的脑洞里塞了个幻想的泡泡……SY 戳开一看,又是长长的一串数字!

SY 实在是不想思考了,她决定用小学的除法消灭她脑洞里的数字.

题目描述

定义 o p op op 操作意义为将当前数除以 d d d 并向下取整.

SY 现在有 m m m 个“原数”,若一个数经过若干次 o p op op 操作(包括 0 0 0 次)后能变为这个“原数”,那么这个数是可以被这个“原数”所消灭的。注意,“原数”是不会被消耗的.

现在 SY 想问你,对于一个区间 [ l , r ] [l,r] [l,r],在消灭最多个数的前提下最少需要多少个“原数”?

输入格式

第一行 4 4 4 个数,分别是 n , m , d , q n,m,d,q n,m,d,q,分别表示数列 { a } \{a\} {a} 元素个数,SY 拥有的 “原数” 个数, o p op op 操作参数,询问个数。

第二行为 { a } \{a\} {a} 数列,即需要被消灭的数列。

第三行为 m m m 个“原数”。

接下来 q q q 行,每行两个数 l l l r r r,表示询问区间为 [ l , r ] [l,r] [l,r]

输出格式

按照询问顺序,每一行输出一个整数表示答案.

输入输出样例

输入 #1
2 3 3 3
0 20
6 6 6
1 1
2 2
1 2
输出 #1
0
1
1
输入 #2
6 3 3 3
6 5 10 15 19 7
2 5 10
1 6
1 4
4 6
输出 #2
3
3
2

说明/提示

样例解释:

#样例1 20 20 20 经过一次 o p op op 操作(除以 3 3 3 向下取整)可以变成 6 6 6,而 0 0 0 不能经过若干次 o p op op 操作变成 6 6 6

所以区间 [ 1 , 1 ] [1,1] [1,1] 最多消灭 0 0 0 个数,消灭最多数前提下最少需要 0 0 0 个 “原数”,区间 [ 1 , 2 ] , [ 2 , 2 ] [1,2],[2,2] [1,2],[2,2] 最多消灭 1 1 1 个数,消灭最多数前提下最少需要 1 1 1 个 “原数” 。

#样例2 2 2 2 能消灭 { 6 , 19 , 7 } \{6,19,7\} {6,19,7} 5 5 5 能消灭 { 5 , 15 } \{5,15\} {5,15} 10 10 10 能消灭 { 10 } \{10\} {10} , 所以区间 [ 1 , 6 ] , [ 1 , 4 ] [1,6],[1,4] [1,6],[1,4] 最少能用所有 “原数” 全部消灭,区间 [ 4 , 6 ] [4,6] [4,6] 能用 2 , 5 2,5 2,5 全部消灭。

数据范围:

对于 30 % 30\% 30% 的数据: n ≤ 100 , m ≤ 10 , d = 2 , q ≤ 10 n\le100,m\leq10, d=2, q\le 10 n100,m10,d=2,q10

对于 100 % 100\% 100% 的数据: n ≤ 5 × 1 0 5 , m ≤ 60 , 2 ≤ d ≤ 10 , q ≤ 1 0 6 , 0 ≤ a i , b i ≤ 2 63 n\le5\times 10^{5},m\leq60,2\leq d\leq10,q\le10^{6},0\le a_i,b_i\le 2^{63} n5×105,m60,2d10,q106,0ai,bi263

在这里插入图片描述
特殊性质:数据经过构造。

题解

比较好想,因为 d d d是固定的,所以一个数能不能被原数消灭是可以预处理出来的。同时原数也有可能被另一个原数消灭,所以我们需要先“化简”一下原数集合,把能被其他原数消灭的原数删去,再将原数排好序,方便后续的查找。

因为一个原数可以消灭多个数,需要合并区间的信息,看到 m ≤ 60 m\le 60 m60,直接明示状态压缩,用一个long long 63 63 63个二进制位就可以完美表示出整个区间需要的原数状态,并且能做到 O ( 1 ) O(1) O(1)合并。再看到询问 1 0 6 10^6 106,明示卡 O ( l o g 2 n ) O(log_2n) O(log2n)算法,就自然想到 S T \mathcal{ST} ST表,于是这题就做完了。

代码

思路简单,但是为什么没有一次过呢,又双叒叕是因为™的long long,👴吐了。

#include<bits/stdc++.h>
#define MAX LONG_LONG_MAX
using namespace std;
const int M=5e5+5;
int n,m,d,q,lg2[M];
long long st[M][20],que[M],ori[65],pow2[65];
void deal(int v)
{
    long long x=que[v];
    for(int p;x;x/=d)
    {
        p=lower_bound(ori+1,ori+1+m,x)-ori;
        if(ori[p]==x){st[v][0]=pow2[p-1];break;}
    }
}
int div(long long x){int r=0;for(;x;x>>=1)if(x&1)++r;return r;}
int ask(int le,int ri)
{
    int lg=lg2[ri-le+1];
    return div(st[le][lg]|st[ri-pow2[lg]+1][lg]);
}
void in()
{
    scanf("%d%d%d%d",&n,&m,&d,&q);
    for(int i=1;i<=n;++i)scanf("%lld",&que[i]);
    for(int i=1;i<=m;++i)scanf("%lld",&ori[i]);
}
void ac()
{
    sort(ori+1,ori+1+m);
    m=unique(ori+1,ori+1+m)-1-ori;
    int tmp=0;
    for(int i=m;i>1;--i)
    for(long long j=ori[i];j;j/=d)if(binary_search(ori+1,ori+i,j)){ori[i]=MAX;++tmp;break;}
    sort(ori+1,ori+1+m);
    m-=tmp;
    lg2[1]=0;for(int i=2;i<=n;++i)lg2[i]=lg2[i>>1]+1;
    pow2[0]=1;for(int i=1;i<=63;++i)pow2[i]=pow2[i-1]<<1;
    for(int i=1;i<=n;++i)deal(i);
    for(int i=1;i<=lg2[n];++i)for(int j=n-pow2[i]+1;j;--j)st[j][i]=st[j][i-1]|st[j+pow2[i-1]][i-1];
    for(int i=1,a,b;i<=q;++i)scanf("%d%d",&a,&b),printf("%d\n",ask(a,b));
}
int main()
{
    in(),ac();
    //system("pause");
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值