1 条题解

  • 0
    @ 2026-5-7 15:51:15

    抽象思维题。

    显然我们可以直接 dp,fif_i 为将 ii 变成 0 所需的最小步数。

    显然 $f_x=\min _{i=1}^{n} f_{\left \lfloor \frac{x}{a_i} \right \rfloor }+1$,然后状态是 O(n)O(n) 的但是转移不是一个区间,优化不下去了。

    发现这玩意显然是单调的。设 pxp_x 为在质数集中最大的能整除 xx 的数。

    那么我们有 fif[i+1,i+pi1]f_i \to f_{[i+1,i+p_i-1]}。发现左端点单调递增,直接队列优化一下即可。

    #include<bits/stdc++.h>
    // #define int long long
    #define endl '\n'
    using namespace std;
    const int mod=998244353,inf=0x3f3f3f3f3f3f3f3f;
    const int N=1e5+10,M=1e7+10,lim=1e7+1;
    int n,m,l=1;
    int a[N],f[M],pm[M];
    queue<pair<int,pair<int,int>>>q;
    signed main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0),cout.tie(0);
    	cin >> n >> m;
    	for ( int i = 1 ; i <= n ; i++ )cin >> a[i];
    	sort(a+1,a+1+n);
    	pm[0]=a[n];
    	for ( int i = 1 ; i <= n ; i++ )
    	{
    		for ( int j = a[i] ; j <= lim ; j+=a[i] )
    		{
    			pm[j]=a[i];
    		}
    	}
    	for ( int i = 1 ; i <= n ; i++ )
    	{
    		if(1ll*l*a[i]>lim)
    		{
    		    l=lim;
    		    break;
    		}
    		l*=a[i];
    	}
    	memset(f,0x3f,sizeof(f));
    	q.push({0,{0,0}});
    	for ( int i = 0 ; i < l ; i++ )
    	{
    		while(q.front().second.second<i)q.pop();
    		f[i]=q.front().first;
    		q.push({f[i]+1,{i+1,i+pm[i]-1}});
    	}
    	while(m--)
    	{
    		int x;
    		cin >> x;
    		if(x>=l)cout << "oo\n";
    		else cout << f[x] << endl;
    	}
    	return 0;
    }
    /*
    n+m
    100
    >=lcm显然无解
    这个好证。
    <max显然答案为1,用max进行操作即可
    然后答案显然不降
    哎呦512M直接dp预处理出1~lcm的全部答案即可
    显然每次操作我们要让数尽可能变小
    那么我们就有nm做法。 
    翻了
    这个dp我们考虑被动转移
    这样的话转移过去就是一个区间。
    这玩意不好用数据结构维护
    但是我们发现f数组有单调性并且区间左端点单调上升
    用一个队列存储所有转移
    到i的时候就弹出所有不合法转移(r<i)
    然后取出队头进行转移,因为单调性,这样是正确的
    瓶颈在于筛最大质因子的过程
    似乎是ln,又似乎是loglogn?
    跑得飞快就是了 
    */
    
    • 1

    「BalticOI 2013」Brunhilda 的生日 Brunhilda’s Birthday

    信息

    ID
    4801
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者