zoukankan      html  css  js  c++  java
  • CF261E Maxim and Calculator

    洛咕

    二元组$ (a,b)(,可以变成) (a,b+1)(或) (ab,b)(.你有初始二元组) (1,0)(,给你区间) [l,r](,和一个整数) p(,在区间内选一个数) x(,使) (1,0)(在不超过) p(步变化后,第一维的值变成) x(,求) x$的个数.(2<=l<=r<=1e9,1<=p<=100)

    分析:思维难度大.首先要发现最大质因数大于p的数一定不能在p步之内得到(假设最大质因数为maxn,因为该数一定要是乘上maxn才能得到,而maxn是个质数,只能每次+1得到,要加maxn-1次,然后再乘以次,总共maxn次)

    所以我们线性筛先筛出p以内的所有质数,然后一个dfs求出所有最大质因数小于p的数放入a数组中(p最大为100,此时大概(3*10^6)个),现在我们考虑判断a数组中的数能否在p步之内得到即可.

    然后我们把a数组从小到大排序,枚举i为步数,j为当前判断到的数为a[j],设(f[j])表示要得到(a[j])要乘的最少次数(记住f数组只计算乘的次数,不计算加1的次数),则当(a[j]*i=a[k])时,(f[k]=min(f[k],f[j]+1))

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=105;
    const int M=5000005;
    int l,r,p,tot,n,ans;
    int v[N],prime[N];
    int a[M],visit[M],f[M];
    inline void get_prime(){
    	for(int i=2;i<=p;++i){//线性筛素数筛出p以内的所有质数
    		if(!v[i]){
    			v[i]=i;
    			prime[++tot]=i;
    		}
    		for(int j=1;j<=tot;++j){
    			if(prime[j]*i>p||prime[j]>v[i])break;
    			v[prime[j]*i]=prime[j];
    		}
    	}
    }
    //dfs求出所有最大质因数小于p的数
    //num表示当前考虑到了第num个质数,now表示当前质数的乘积
    inline void dfs(int num,ll now){
    	if(num>tot)return;//全都考虑完了
    	dfs(num+1,now);//不选当前的这个数
    	while(1){//可以乘当前这个质数无数次
    		now*=prime[num];//累乘
    		if(now>r)break;//超过范围
    		a[++n]=now;//记录
    		dfs(num+1,now);//考虑下一个数
    	}
    }
    int main(){
    	l=read();r=read();p=read();
    	get_prime();dfs(1,1);
    	a[++n]=1;sort(a+1,a+n+1);
    	f[1]=0;for(int i=2;i<=n;++i)f[i]=1e9;
    	for(int i=2;i<=p;++i){
    		for(int j=1,k=1;j<=n;++j){
    			while(k<=n&&a[j]*i>a[k])++k;
    			if(k>n)break;if(a[j]*i<a[k])continue;
    			f[k]=min(f[k],f[j]+1);
    			if(visit[k]||f[k]+i>p||a[k]<l)continue;
    //解释一下第二个,f数组记录的要得到a[k]需要乘的步数,i是要加1的步数,两者相加才是总步数.
    			visit[k]=1;++ans;
    		}
    	}
    	printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    Flutter form 的表单 input
    FloatingActionButton 实现类似 闲鱼 App 底部导航凸起按钮
    Flutter 中的常见的按钮组件 以及自 定义按钮组件
    Drawer 侧边栏、以及侧边栏内 容布局
    AppBar 自定义顶部导航按钮 图标、颜色 以及 TabBar 定义顶部 Tab 切换 通过TabController 定义TabBar
    清空路由 路由替换 返回到根路由
    应对ubuntu linux图形界面卡住的方法
    [转] 一块赚零花钱
    [转]在树莓派上搭建LAMP服务
    ssh保持连接
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11305644.html
Copyright © 2011-2022 走看看