SSY20240811提高组T2题解__精分的计算器

题面

题面描述

由于SZY经常在月黑风高夜游荡,他的计算器患上了精神分裂,分出了两个人格(存储单元)。一开始,第一个单元包含数字1,第二个单元包含数字0。于是,它就不能进行正常的计算了,而只支持以下两种操作:

假设第一个单元的数字为 a a a,第二个单元的数字为 b b b,那么将第二个单元的数字改成 b + 1 b+1 b+1

假设第一个单元的数字为 a a a,第二个单元的数字为 b b b,那么将第一个单元的数字改成 a × b a\times b a×b

现在SZY想知道,有多少个正整数 x ( l ≤ x ≤ r ) x (l\le x\le r) x(lxr) 满足存在一种方式可以让计算器从初始状态开始,操作不超过p步之后第一个单元中的数字为 x x x

输入输出格式

输入格式

共一行,为三个空格隔开的整数。

输出格式

输出仅一行,包含一个整数,即为问题所求。

输入输出样例

输入数据 1
2 10 3
输出数据 1
1
输入数据 2
2 111 100
输出数据 2
106
输入数据 3
2 111 11
输出数据 3
47

数据规模

对于100%的数据, 2 ≤ l ≤ r ≤ 1 0 9 2\le l\le r\le10^9 2lr109

题解

思路

我们可以轻易地发现, 对于一个数, 如果它含有大于 p p p的质因数, 那么这个数一定不能被选中
所以我们可以使用 d f s dfs dfs来找出所有( ≤ r \le r r)含小于等于 p p p的质因数的数
代码如下:

int num[MAXN],cnt;//能用p以内质因数表示出来的数 
bool vis[MAXN];
int prime[100],tot=0;

void getpri(){//素数筛
	for(int x=2;x<=p;x++){
		if(!vis[x]){
			prime[++tot]=x;
		}
		for(int y=1;y<=tot;y++){
			vis[x*prime[y]]=1;
			if(x%prime[y]==0){
				break;
			}
		}
	}
	return;
}
void dfs(int i,int num_now){
	num[++cnt]=num_now;
//	cout << cnt << ':' << i << ' ' << num_now << endl;
	for(int x=i;x<=tot;x++){//从i开始, 防止i之前的造成重复
		if(num_now*prime[x]<=r){
			dfs(x,num_now*prime[x]);
		}else{
			break;
		}
	}
}

根据我的严谨的计算(其实就是把最大值带入输出), c n t ( 符合上述所说数的个数 ) cnt_{(符合上述所说数的个数)} cnt(符合上述所说数的个数)的最大值为 2944730 2944730 2944730, 即为 3 × 1 0 6 3\times 10^6 3×106即可, 这就是MAXN 的大小

现在, n u m num num数组里存的都是只含有 p p p以内因数的数, 现在我们要在其中找出能在 p p p步内走出的数


我们定义一个数组 v v i s [ y ] vvis[y] vvis[y], 表示 n u m [ y ] num[y] num[y]是否被选中,
(注: y y y记录的是下标, 而不是一个具体的数, v v i s [ y ] vvis[y] vvis[y] 中的 y y y 对应的是 n u m [ y ] num[y] num[y].

我们再定义一个状态 d p [ y ] dp[y] dp[y], 表示 n u m [ y ] num[y] num[y]需要多少次乘法到达( a = a × b a=a\times b a=a×b操作).
(注: 同上, y y y同样也只是一个下标)

现在枚举计算器的第二人格 x x x(即题目中的 b b b)作为倍数, 再枚举一个基本数z( ∈ n u m \in num num, 以下标形式枚举), 乘起来得到一个新数 y y y如下:
n u m [ y ] = n u m [ z ] × x num[y]=num[z]\times x num[y]=num[z]×x
于是我们可以轻易地推出以下方程式:
d p [ y ] = m i n ( d p [ y ] , d p [ z ] + 1 ) ( 多使用一次乘法 ) dp[y]=min(dp[y],dp[z]+1)_{(多使用一次乘法)} dp[y]=min(dp[y],dp[z]+1)(多使用一次乘法)
但是, n u m [ y ] num[y] num[y]需要满足以下条件, 才能认定它是合法的

  1. l ≤ n u m [ y ] l\le num[y] lnum[y]
  2. n u m [ y ] ≤ r      num[y]\le r\;\; num[y]r(也可以表示为 y ≤ c n t y\le cnt ycnt)
    以上两点是为了这个数在 l , r l,r l,r范围内
  3. v i s [ y ] = = 0 vis[y]==0 vis[y]==0
    这个数没有被选过
  4. d p [ y ] + x ≤ p dp[y]+x\le p dp[y]+xp
    总步数在 p p p以内, 我们定义的 d p [ y ] dp[y] dp[y]是使用乘法的次数, x x x既是使用加法的次数

只要符合以上四个条件, 就可以累加答案了(^_^)

AC Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define MAXN 2944730+100


bool vis[10086],vvis[MAXN];
int prime[100],tot=0;
int l,r,p;
int dp[MAXN],b[MAXN];
int num[MAXN],cnt;//能用100以内质因数表示出来的数 

void getpri(){
	for(int x=2;x<=p;x++){
		if(!vis[x]){
			prime[++tot]=x;
		}
		for(int y=1;y<=tot;y++){
			vis[x*prime[y]]=1;
			if(x%prime[y]==0){
				break;
			}
		}
	}
	return;
}

void dfs(int i,int num_now){
	num[++cnt]=num_now;
//	cout << cnt << ':' << i << ' ' << num_now << endl;
	for(int x=i;x<=tot;x++){
		if(num_now*prime[x]<=r){
			dfs(x,num_now*prime[x]);
		}else{
			break;
		}
	}
}


signed main(){
	cin >> l >> r >> p;
	getpri();
	dfs(1,1);
	sort(num+1,num+1+cnt);
	memset(dp,0x7f,sizeof(dp));
    dp[1]=0;
	vvis[1]=1; 
    int ans=0;
    for(int x=2;x<=p;x++){
    	int y=1;
    	for(int z=1;z<=cnt;z++){
    		bool bol=0;
    		while(num[y]!=num[z]*x){
    			y++;
    			if(y>cnt){
    				bol=1;
    				break;
				}
			}
			if(bol){
				break;
			}
			dp[y]=min(dp[y],dp[z]+1);
			if(dp[y]+x<=p && num[y]>=l && vvis[y]==0){
				vvis[y]=1;
				ans++;
			}
    	}
	}
    cout << ans;
	return 0;
}

补充

如果上面对 n u m [ y ] num[y] num[y]的第四个约束条件没看懂的话, 可以参考下图:
在这里插入图片描述
a a a增加的途径只有 a × b a\times b a×b, 让 b b b增加的途径只有 b + 1 b+1 b+1
所以 d p [ y ] + x 是需要的总步数 dp[y]+x是需要的总步数 dp[y]+x是需要的总步数

  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误是因为 `legend` 函数的第一个输入参数 `ssy{1}` 和第二个输入参数 `ssy{2}` 的类型不正确导致的。`ssy` 可能是一个单独的数,而不是一个包含两个数的单元格数。请确保 `ssy` 是一个单元格数,并且包含两个数。你可以使用 `celldisp(ssy)` 查看 `ssy` 的类型和内容,以确保它符合要求。如果 `ssy` 不包含两个数,则需要修改代码以正确设置 `ssy` 的值。 ### 回答2: 这段代码出错的原因可能是在第31行的legend函数中的参数配置有误。根据给出的代码,legend函数应该是用于添加图例的。根据我对legend函数的了解,它的参数应该是一个字符串数,可以用于标识图中的每个数据系列。 在这个具体的错误中,可能是ssy这个变量没有被正确地定义或者存在问题。可以先检查一下代码前面是否有对ssy的定义,或者看一下ssy的数据类型是否正确。另外,在legend函数的参数中,0.2和0.3这两个数值可能是指定图例的位置或者大小,也可以检查一下这些数值是否符合函数的要求。 总之,确定代码中的ssy变量是否正确定义,并检查legend函数的参数是否符合函数要求,可以帮助解决这个错误。如果还有其他代码和错误信息提供,我们可以进行更准确的分析和回答。 ### 回答3: 在图表绘制过程中,调用了函数 legend(),并传入了参数 ssy{1}、ssy{2}、0.2和0.3。然而,在第31行中,函数调用出现了错误,导致程序无法正常执行下去。 出现错误的原因可能有多种可能性。首先,可能是因为函数 legend() 在当前环境中未定义或未正确加载,导致调用失败。此外,还有可能是传入的参数有误,比如 ssy{1} 和 ssy{2} 可能不存在或者数据类型不匹配。还有一种可能是传入的透明度参数0.2和0.3超出了函数允许的范围,导致错误。 为了解决这个问题,我们可以尝试以下几个步骤。首先,确认函数 legend() 是否在当前环境中正确加载,可以查看相关的库是否被正确导入。如果没有正确加载,需要加载相关的库或更新软件版本。其次,检查变量 ssy{1} 和 ssy{2} 是否存在或数据类型是否正确,可以使用打印语句或调试工具来检查变量的值和类型。最后,可以尝试更改透明度参数的值,确保其在合理的范围内。 总之,出现 sigma_masi_0707 (第 31 行) legend(ssy{1},ssy{2},0.2,0.3) 的错误可能是由函数未定义或加载失败、参数传递错误或透明度超出范围等原因引起的。通过逐步排除可能的问题,并针对性地进行修复,可以解决这个错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值