https://www.luogu.org/problemnew/show/T14200
题目描述
LYK定义了一个新的计算。具体地,一开始它有两个数字a和b。每一步,它可以将b增加1,或者将a乘上b。
也就是说(a,b)经过一次操作后可以变成(a,b+1)或者(a*b,b)。再经过一次操作可以变成(a,b+2)或者(a*(b+1),b+1)或者(a*b,b+1)或者(a*b*b,b)。接下来都类似……它认为只有在这个括号左侧的数字才是有意义的,并且它想执行的操作数不会很多。
具体的,如果LYK能通过不超过p步,使得这个括号内左侧的数字变成x,那么x就是一个有意义的数字!
但zhw觉得这个题目太难了,会为难大家,于是他将这个问题中初始的a定义为了1,把b定义为了0。
LYK想知道在一段区间[L,R]中,存在多少有意义的数字。
输入输出格式
输入格式:
第一行3个数分别表示L,R,p。
输出格式:
一个数表示答案。
输入输出样例
输入样例#1:
1 100 10
输出样例#1:
46
输入样例#2:
233 233333333 50
输出样例#2:
332969
说明
对于30%的数据L,R<=10。
对于另外20%的数据p<=20。
对于70%的数据1<=L<=R<=1000,1<=p<=50。
对于90%的数据1<=L<=R<=1000000,1<=p<=50。
对于100%的数据1<=L<=R<=500000000,1<=p<=50。
这个题目的暴力很好写,开个桶,90%的数据就过了。有机会要重新造个数据。当数据范围到5e8的时候,我们要所有可能的数。因为题目总步数限制50步,那么进行多次加或乘得到的数的总数并不特别多,打表看看,不会证明。因为b只能进行加一操作,要得到一个较大数的时候就需要来乘b,要得到一个a,一定是通过乘法得到的。虽然得到这个数的途径很多,但一个数能否得到我们可以通过唯一分解来判定。因次,我们找出50步范围内的所有素数,在R要求的范围内统计。统计通过dfs来完成,要不重复的计数,我们从大的质数开始,不断乘自己,越界了就去乘更小的数。这样找出不限制步数能找到的所有可能生成的数。排序待用。这样找到的数不一定是最优步数,比如42=7*3*2得到的,需要7+3=10步,而最优是7*6,需要7+2=9步。
然后判断p步能否达到,在走*i的情况下,如果b[k]*i能得到b[j],则b[j]=min(b[k]+1)
参考代码:当然是抄std了,不过的按照自己的理解重新写了下。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
long long cnt,i,a[105],b[3000005],o,j,dp[3000005],l,r,p,k,sum;
bool FLAG,v[3000005];
void dfs(long long y,long long z) {
b[++cnt]=y;
if(y*a[z]<=r)dfs(y*a[z],z);
for (int i=z-1;i>0;i--)
if(y*a[i]<=r)dfs(y*a[i],i);
}
int main() {
scanf("%lld%lld%lld",&l,&r,&p);
for (i=2; i<=50; i++) {
FLAG=true;
for (j=2; j<i; j++)
if (i%j==0) FLAG=false;
if (FLAG) a[++o]=i;
}
dfs(1,o);
sort(b+1,b+cnt+1);
for (i=2; i<=cnt; i++) dp[i]=105;//dp[1]=0;
for (i=2; i<=p; i++) {//p,步数
j=1;
for( k=1;b[k]*i<=b[cnt];k++){
while(i*b[k]>b[j])j++;
// cout<<" w"<<i<<" "<<j<<" "<<k<<" dp"<<b[k]<<" "<<b[j]<<endl;
if(b[k]*i==b[j]) {
if (dp[k]+1<dp[j]) dp[j]=dp[k]+1;
// cout<<i<<" "<<j<<" "<<k<<" dp"<<dp[k]<<" "<<dp[j]<<endl;
if (dp[j]+i<=p) v[j]=1;
j++; }
}
/* k=1;
for (j=1; j<=cnt; j++)
if (b[j] % i==0) {//怎样用最少的步数得到这些数呢
if (dp[k]+1<dp[j]) dp[j]=dp[k]+1;
k++;
if (dp[j]+i<=p) v[j]=1;
}
*/
}
v[1]=1;
for (i=1; i<=cnt; i++) if (b[i]>=l && v[i]) sum++;
cout<<sum;
return 0;
}