题解:AT_arc120_f [ARC120F] Wine Thief

Problem Link

[ARC120F] Wine Thief

题外话

“求和”看成“求有多少个不同值”,卡了许久,收获良多。

题面翻译

给定含有 \(n\) 个元素的序列 \(\{A\}\),从中选出 \(k\) 个不相邻的数,求所有可能的和。

Solution

直接做还是太难了,于是考虑先做简单版:如果是在环上选的呢?

定义 \(f_{i,j}\) 为选到第 \(i\) 个点,选择了 \(j\) 个点的和,值为 \(\binom{i-j+1}{j}\)

因为是在环上,所以每个点对答案的贡献都是一样的,值为 \(a_i \times f_{n-3, k-1}\),进行递推即可。

这时候再转回来思考对于序列的操作,发现除了两端都选之外,情况与环上无异。

\(F_{l, r, k}\) 为在区间 \([l, r]\) 中选 \(k\) 个数字的价值,令 \(len = r-l+1\),则:

\[ F_{l, r, k} = f_{len-3, k-1} \times (sum_r-sum_{l-1}) + f_{len-4, k-2} \times (a_l+a_r) + F(l+2, r-2, k-2)。 \]

时间复杂度为 \(O(n)\) 的 dp。

代码

// written by Naught
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define Maxn 300005
#define Mod 998244353
#define fo(i, l, r) for (int i = l; i <= r; ++i)
#define fr(i, r, l) for (int i = l; i >= r; --i)
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21], *p1 = buf, *p2 = buf;
inline int read(int x=0, bool f=0, char c=getchar()) {for(;!isdigit(c);c=getchar()) f^=!(c^45);for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);return f?-x:x;}

ll hts(ll a, ll b)
{
    ll res = 1;
    while(b)
    {
        if(b&1) (res *= a) %= Mod;
        (a *= a) %= Mod, b >>= 1;
    }
    return res;
}

int n, k, a[Maxn];
ll fac[Maxn], inv[Maxn], sum[Maxn];

void Init(ll n)
{
    fac[0] = 1;
    fo(i, 1, n) fac[i] = fac[i-1]*i%Mod;
    inv[n] = hts(fac[n], Mod-2);
    fr(i, 0, n-1) inv[i] = inv[i+1]*(i+1)%Mod;
}

ll C(ll i, ll j) {return fac[i]*inv[j] %Mod * inv[i-j] %Mod;}

ll F(ll l, ll r, ll k)
{
    if(k == 0) return 0;
    if(k == 1) return (sum[r]-sum[l-1]+Mod) % Mod;
    ll len = r - l + 1;
    return (C(len-1-k, k-1) * (sum[r]-sum[l-1]+Mod) % Mod + C(len-1-k, k-2) * (a[l]+a[r]) % Mod + F(l+2, r-2, k-2)) % Mod;
}

int main()
{
    Init(Maxn-5);
    n = read(), k = read(), a[1] = read();;
    fo(i, 1, n) a[i] = read(), sum[i] = (sum[i-1]+a[i]) % Mod;
    printf("%lld", F(1, n, k));
    return 0;
}

Tips

记得考虑边界。

posted @ 2024-10-14 19:00  naughty_Naught  阅读(6)  评论(0编辑  收藏  举报