CF261E Maxim and Calculator

题目大意:

有两个初始参数 $ a=1 $ , $ b=0 $ ,你可以对它们进行两个操作: $ b~+=1 $ 或 $ a~\times =b $ ,最终的 $ a $ 才是你所得到的数 。 现在给你三个数 $ l,r,p $ ,让你求在区间 $ [l,r] $ 内可以用不超过 $ p $ 次操作得到的数的个数。数据范围: $ (2<=l<=r<=10^{9},1<=p<=100) $



$ solution: $

很神仙的一道题,当时看了很久只能想到:每个我所得到的数,一定是若干个可能不同的 $ b $ 的乘积,。又因为 $ b $ 每次只能加1,所以我们如果要用最少的步数得到一个数 $ a $ ,最终 $ b $ 的大小一定是 $ b $ 的最大质因子!同理,最大质因子大于 $ p $ 的数一定不可通过少于 $ p $ 的次数得到

当时的想法是线性筛最大质因子,然后暴力判断,复杂度 $ O(n) $ 显然超时。然后死活没想到可以筛 $ p $ 以下质数所构成的数( $ 10^9 $ 里面不超过 $ 3\times 10^6 $ 个 )!

好吧,回归正题。根据上面我们的分析,所有最大质因子大于 $ p $ 的数一定不可通过少于 $ p $ 的次数得到,所以我们可以找出所有最大质因子在 $ p $ 以内的数。怎么求?这其实等同于求 $ p $ 以内的所有质数可以构造的数(注意题目说 $ 2\leq r $ ,所以不考虑1)(然后我们现线性筛质数,再搜索一下即可)。然后我们发现这样的数不超过 $ 3\times 10^6 $ 个,我们用一个数组 $ a[] $ 存起来。于是我们考虑怎么判断 $ a[] $ 里面的数是否能在 $ p $ 次操作内得到。

首先我们要明白一个点:所有 $ a[] $ 里的数都可以通过 $ a[] $ 里比它小的数构造出来。证明:对于 $ a[] $ 里的数 $ i $ ,如果它的最大质因子为 $ k $ ,那么 $ i/k $ 一定在 $ a[] $ 中,因为 $ i/k $ 的所有质因子都小于 $ p $ 。于是我们考虑 $ f[i][j] $ 表示 $ b $ 的大小为 $ i $ 时 $ j $ 的最小构造步数。我们从小到达枚举 $ b $ ,每个 $ b $ 可以选用很多次,这不就是一个完全背包吗?不过是 $ b $ 要被乘上去而已!注意我们的 $ a[] $ 数组是离散化的,我们先排一遍序,然后用单调队列找到 $ a[k]=a[j]*i $ 即可做到 $ O(1) $ 转移!

$ f[i][k]=f[i][j]+1 \quad (~a[j]\times i=a[k]~) $

复杂度: $ O(p\times 3 \times 10^6) $ ,很勉强



$ code: $

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set> #define ll long long
#define db double
#define rg register int using namespace std; int l,r,p,n; // n表示a数组的大小
int ans,tt; // tt素数个数
int a[3000005]; //最大质因子小于p的数的集合
int f[3000005]; //构造a[i]这个数的最少步数
bool d[3000005]; //是否已经加入贡献
int pr[505]; //素数表
bool vis[505]; //筛素数 inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
} inline void prime(int x){ //线性筛素数
for(rg i=2;i<=x;++i){
if(!vis[i])pr[++tt]=i;
for(rg j=1;j<=tt;++j){
if(i*pr[j]>x)break;
vis[i*pr[j]]=1;
if(!(i%pr[j]))break;
}
}
} //找到最大质因子小于p的数
//等效于我们构造小于p的质数所能构造的数
inline void dfs(int i,ll v){ //i是当前轮到的质数
if(i>tt)return ;
dfs(i+1,v); //不用这个质数
while(1){
v*=pr[i]; //不断选用这个质数
if(v>r)return ; //退出
dfs(i+1,v);
a[++n]=v; //记录这个数
}
} int main(){
l=qr(); r=qr(); p=qr();
prime(p); dfs(1,1); a[++n]=1; //预处理
sort(a+1,a+n+1); f[1]=0;
for(rg i=2;i<=n;++i) f[i]=101; //赋初值无穷大
for(rg i=2;i<=p;++i){
for(rg j=1,k=1;j<=n;++j){
while(k<=n&&a[j]*i>a[k])++k; //因为a数组离散化,所以单调队列查找
if(k>n)break; if(a[j]*i!=a[k])continue;
f[k]=min(f[k],f[j]+1); //更新步数
if(d[k]||f[k]+i>p||a[k]<l)continue; //注意第二个判断
d[k]=1; ++ans; //步数在p范围内,计入答案
}
}
printf("%d\n",ans);
return 0;
}

CF261E Maxim and Calculator (质数,完全背包)的更多相关文章

  1. CF261E Maxim and Calculator

    CF261E Maxim and Calculator 洛谷评测传送门 题目描述 Maxim has got a calculator. The calculator has two integer ...

  2. [CF261E]Maxim and Calculator_搜索_欧拉筛素数_动态规划

    Maxim and Calculator 题目链接:https://www.luogu.org/problem/CF261E 数据范围:略. 题解: 考试的时候只会暴力,学弟太强了$\%\%\% Or ...

  3. Codeforce 水题报告

    最近做了好多CF的题的说,很多cf的题都很有启发性觉得很有必要总结一下,再加上上次写题解因为太简单被老师骂了,所以这次决定总结一下,也发表一下停课一星期的感想= = Codeforces 261E M ...

  4. 考前停课集训 Day2 非

    因为太长了 所以一天一天分开发 Day2 昨天晚上没开黑车 没脱衣服就睡了 可能是我难受了…… 新的一天. 早上好. 我没去晨跑,早上先和团长集合了,没看见rkbudlo来 于是就先吃饭了 去机房的时 ...

  5. HGOI 20190519 题解

    脑补了一下今天的比赛难度和之前zju-lzw出的题目画风迥异. 难度完全不是一个水平的好伐. Probem A palindrome 给出一个$n$个元素的数组,可以任意指定一个数字$m$让所有$a_ ...

  6. Codeforces 922 思维贪心 变种背包DP 质因数质数结论

    A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...

  7. BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )

    题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...

  8. BZOJ 1025: [SCOI2009]游戏( 背包dp )

    显然题目要求长度为n的置换中各个循环长度的lcm有多少种情况. 判断一个数m是否是满足题意的lcm. m = ∏ piai, 当∑piai ≤ n时是满足题意的. 最简单我们令循环长度分别为piai, ...

  9. hdu 6125 -- Free from square(状态压缩+分组背包)

    题目链接 Problem Description There is a set including all positive integers that are not more then n. Ha ...

随机推荐

  1. 快速入门分布式消息队列之 RabbitMQ(3)

    目录 目录 前文列表 前言 通道 Channel 一个基本的生产者消费者实现 消费者 生产者 运行结果 应用预取计数 应用 ACK 机制 最后 前文列表 快速入门分布式消息队列之 RabbitMQ(1 ...

  2. nginx访问控制用户认证两种方式

    一.用户认证1.首先需要用http来生成密码文件即安装apache :yum install -y httpd 生成密码文件:htpasswd -c /usr/local/nginx/conf/htp ...

  3. c语言字串指针 char*

    c语言中 char* 不仅能存字符串,还能存二进制数据,所以它的用途因使用者而定. char* 在很多使用场景下,是需要存储ascii码为0的元素的,这样就必须注意一个问题,那就是char*的长度. ...

  4. 正则表达式分组(Grouping)

    一 捕获型 (x) 匹配 x ,并且捕获匹配项 const regExp = /(\w+)\s+(\d+)/; const str = 'Android 8'; str.replace(regExp, ...

  5. 卷积神经网络应用于MNIST数据集分类

    先贴代码 import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data mnist = inpu ...

  6. 【Qt开发】事件循环与线程 一

    事件循环与线程 一 初次读到这篇文章,译者感觉如沐春风,深刻体会到原文作者是花了很大功夫来写这篇文章的,文章深入浅出,相信仔细读完原文或下面译文的读者一定会有收获. 由于原文很长,原文作者的行文思路是 ...

  7. Anaconda版本

    1. Anaconda各种版本 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 2. 多个Python环境 conda info -e c ...

  8. rename批量修改文件名

    批量改名: 如文件,批量修改,把hello去掉[root@localhost wang]# ll-rw-r--r-- 1 root root 0 5月 14 02:36 a.hello.txt-rw- ...

  9. RPM包或源码包

    安装RPM包或源码包 点击vmware右下角光驱连接. 安装rpm包 -i:表示安装 -v:表示可视化 -h:表示显示安装进度 (同时使用) --force:表示强制安装,即使覆盖属于其他包的文件也要 ...

  10. ssh-config的使用

    使用SSH的配置文件可以在很大程度上方便各种操作,特别适应于有多个SSH帐号.使用非标准端口或者写脚本等情况. man ssh_config 可以查看手册 如果之前是用密码方式来登录SSH,需要先改用 ...