CF2183E LCM is Legendary Counting Master

第二个约束条件一看就不好做,尝试转化。首先,根据最大公约数的求法,不难想象到 \(\frac {1} {\operatorname{lcm}(a_{i},a_{i+1})}=\frac {\gcd(a_{i},a_{i+1})} {a_{i} a_{i+1}}\)。题目中要求 \(\sum \frac {1} {\operatorname{lcm}} \geq 1\),考虑反向放缩,看看 \(\sum \frac {1} {\operatorname{lcm}}\) 会不会小于等于什么

\(a<b\) 时,\(\gcd(a,b) = \gcd(b \% a,a) \leq b \% a \leq b-a\),所以 \(\frac {1} {\operatorname{lcm}(a_{i},a_{i+1})} \leq \frac {a_{i+1}-a_{i}} {a_{i} a_{i+1}} = \frac {1} {a_{i}} - \frac {1} {a_{i+1}}\)。对于最后一项,我们可以放缩成 \(\frac {1} {a_{n}}\),这样的话 \(\sum \frac {1} {\operatorname{lcm}} \leq \frac {1} {a_1} - \frac {1} {a_2} + \frac {1} {a_2} - \frac {1} {a_3} + ... + \frac {1} {a_n} =\frac {1} {a_1} \leq 1\)。所以 \(\sum \frac {1} {\operatorname{lcm}}\) 就必须等于 \(1\)

既然如此,观察我们的取等条件。首先,\(a_1\) 必须等于 \(1\)。这样也满足了最后一项 \(\gcd(a_n,a_1)=a_1\)。考虑中间的项。因为 \(\gcd(a_i,a_{i+1})=a_{i+1}-a_{i}\),令 \(a_{i+1}-a_i=d\),那么 \(a_{i+1}=a_i+d\),其中 \(d\)\(a_i\) 的一个因数。因此我们可以使用动态规划来解决这个问题。

\(f_{i,j}\) 表示考虑前 \(i\) 个数,第 \(i\) 个数是 \(j\) 的方案数。转移就是枚举每一个 \(i\),然后枚举 \(j\),对于 \(j\) 的所有因数 \(k\)\(f_{i,j}\) 对于 \(f_{i+1,j+k}\) 有贡献。

\(code\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e3+5,mod=998244353;
int T,n,m;
int a[N];
ll f[N][N];
vector<int> d[N];
inline void prework()
{
    for (int i=1;i<=3000;++i)
    {
        for (int j=i;j<=3000;j+=i)
        {
            d[j].push_back(i);
        }
    }
}
inline void solve()
{
    cin>>n>>m;
    for (int i=1;i<=n;++i) cin>>a[i];
    if (a[1]!=0&&a[1]!=1)
    {
        cout<<"0"<<endl;
        return;
    }
    for (int i=1;i<=n;++i)
    {
        for (int j=1;j<=m;++j)
        {
            f[i][j]=0;
        }
    }
    f[1][1]=1;
    for (int i=1;i<n;++i)
    {
        if (a[i]!=0) 
        {
            if (!f[i][a[i]])
            {
                cout<<"0"<<endl;
                return;
            }
            for (int j:d[a[i]])
            {
                if (a[i]+j>m-n+i+1) break;
                f[i+1][a[i]+j]=(f[i+1][a[i]+j]+f[i][a[i]])%mod;
            }
        }
        else
        {
            for (int j=i;j<=m-n+i;++j)
            {
                if (f[i][j])
                {
                    for (int k:d[j])
                    {
                        if (j+k>m-n+i+1) break;
                        f[i+1][j+k]=(f[i+1][j+k]+f[i][j])%mod;
                    }
                }
            }
        }       
    }
    if (a[n]!=0) cout<<f[n][a[n]]<<endl;
    else
    {
        ll ans=0;
        for (int i=n;i<=m;++i) ans=(ans+f[n][i])%mod;
        cout<<ans<<endl;
    }
}
int main()
{
    // freopen("a.in","r",stdin);
    // freopen("a.out","w",stdout);
    ios::sync_with_stdio(false);
    prework();
    cin>>T;
    while (T--) solve();
    return 0;
}
posted on 2026-02-07 17:24  Z_S_R  阅读(0)  评论(0)    收藏  举报