【CF261E】Maxim and Calculator

题目

题目链接:https://www.luogu.com.cn/problem/CF261E
二元组\((a,b)\),可以变成\((a,b+1)\)\((ab,b)\)
你有初始二元组\((1,0)\),给你区间\([l,r]\),和一个整数\(p\),在区间内选一个数\(x\),使\((1,0)\)在不超过\(p\)步变化后,第一维的值变成\(x\),求\(x\)的个数。

思路

首先\(p\leq 100\),这意味着\(b\)最大是\(100\)
那么如果一个数\(x\)存在一个质因子\(d\),且\(d>p\),那么显然在\(p\)步之内是没法使\(a\)变成\(d\)的。
所以先\(dfs\)\([1,r]\)之内所有质因子都在\(p\)以内的数字。在\([1,10^9]\)中这样的数字不会超过\(3\times 10^6\)个。
然后设\(f[i][j]\)表示\(a,b\)分别等于\(i,j\)时的最小转移次数。做背包即可。

\[f[i][j]=min(f[\frac{i}{j}][j],f[i][j-1])+1 \]

注意实际时\(i\)应该为上文求出来的数列的第\(i\)项,且第二维应滚动。

代码

#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=3000010,M=110;
const int prime[26]={0,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,n,m,pos,ans,a[N],f[2][N];
bool vis[N];

void dfs(int x,int dep,int last)
{
	//if (dep>m) return;
	a[++n]=x;
	for (int i=last;i<=pos;i++)
		if (1LL*x*prime[i]<=(long long)r)
			dfs(x*prime[i],dep+1,i);
	
}

int main()
{
	scanf("%d%d%d",&l,&r,&m);
	pos=25;
	for (int i=1;i<=25;i++)
		if (prime[i]>m)
		{
			pos=i;
			break;
		}
	dfs(1,0,1);
	sort(a+1,a+1+n);
	memset(f,0x3f3f3f3f,sizeof(f));
	f[0][1]=0;
	for (register int j=1;j<=m;j++)
	{
		int k=1;
		for (register int i=1;i<=n;i++)
		{
			while (a[i]>a[k]*j && k<=n) k++;
			if (a[k]*j==a[i]) f[j&1][i]=min(f[j&1][k],f[(j+1)&1][i])+1;
				else f[j&1][i]=f[(j+1)&1][i]+1;
			if (!vis[i] && l<=a[i] && a[i]<=r && f[j&1][i]<=m)
			{
				vis[i]=1;
				ans++;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-02-06 16:31  stoorz  阅读(335)  评论(0编辑  收藏  举报