正题
题目链接:https://jzoj.net/senior/#contest/show/3008/2
题目大意
两个数(a,b)(a,b)(a,b),两个操作
- (a,b)−>(a,b+1)(a,b)->(a,b+1)(a,b)−>(a,b+1)
- (a,b)−>(a∗b,b)(a,b)->(a*b,b)(a,b)−>(a∗b,b)
求ppp步以内aaa能到达[l,r][l,r][l,r]之间的多少个数
解题思路
到达xxx的最小步骤就是将xxx分解乘若干个数的乘积,使得最大数+数的个数最小。
首先答案肯定是能被1∼p1\sim ~ p1∼ p之间的质数的乘积表示出来的,发现这些数并不多,可以用dfsdfsdfs搜索出来并排序。
然后dpdpdp,fif_{i}fi表示到达aia_iai的最少操作222,然后枚举操作111的数量进行转移,也就是枚举最大数jjj,找到一个ak∗j=aia_k*j=a_iak∗j=ai
然后有转移fi=min{fi,fk+1}f_{i}=min\{f_i,f_k+1\}fi=min{fi,fk+1}
时间复杂度O(3∗106∗n)O(3*10^6*n)O(3∗106∗n)
codecodecode
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e6+10;
int pri[25]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
int l,r,P,maxx,ans,a[N],f[N],cnt,z;
bool v[N];
void dfs(int x,int k){a[++cnt]=x;for(int i=k;i<=z;i++){if((long long)x*pri[i]>r) return;dfs(x*pri[i],i);}
}
int main()
{scanf("%d%d%d",&l,&r,&P);while(z<24&&pri[z+1]<=P)z++;dfs(1,0);sort(a+1,a+1+cnt);memset(f,0x3f,sizeof(f));f[1]=0;for(int i=2;i<P;i++){int z=0;for(int j=1;j<=cnt;j++){while(a[z]*i<a[j])z++;if(a[z]*i==a[j])f[j]=min(f[j],f[z]+1);if(i+f[j]<=P)v[j]=1;}}for(int i=cnt;i>=1;i--){if(a[i]<l) break;if(v[i])ans++;}printf("%d",ans);
}