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;
    }
    
    
  • 相关阅读:
    读《大道至简》第6章有感
    Java作业05(动手动脑)
    读《大道至简》第五章有感
    java作业04(动手动脑)
    域名与主机名
    STL 迭代器学习
    数组与链表增删改查效率比较
    智能指针多线程安全问题
    快速乘 学习
    关于TCP三个冗余ACK启动快速重传
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11305644.html
Copyright © 2011-2022 走看看