Enigmatic Partition【二阶差分】-2020牛客暑期多校8

题意:

对于一个数 \(n\) 可以将其拆分为 \(m\) 个数,\(n=a_1+a_2+...+a_m\),要求满足:

  • \(a_i\) 是整数,对于所有的 \(a_i\)\(1\leq a_i \leq n\)
  • \(a_i\leq a_{i+1}\leq a_i+1\) 对于所有的 \(a_i(i<m)\)
  • \(a_m=a_1+2\)

定义 \(f(n)\) 比赛 \(n\) 的划分方案数,对于给定的 \(l\)\(r\) ,求出 \(\sum_{i=l}^{r}{f(i)}\)
\(1\leq l\leq r \leq 10^5\)

分析:

考虑二阶隔项差分,然后往回求出原数列,并预处理前缀和。
这篇博客里讲的很详细:
https://blog.csdn.net/zhangchizc/article/details/107784622?spm=1001.2101.3001.4242

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
ll f[N<<2], sum[N];
void init()
{
    int maxn = 1e5;
    for (int m = 3; m <= maxn;m++)
    {
        for (int a = m; a <= maxn;a+=m)
        {
            f[a + 3]++;
            f[a + m + 1]--;
            f[a + m + 2]--;
            f[a + 2 * m]++;
        }
    }
    for (int i = 3; i <= maxn;i++)
        f[i] += f[i - 2];
    for (int i = 2; i <= maxn;i++)
        f[i] += f[i - 1];
    for (int i = 1; i <= maxn;i++)
        sum[i] = sum[i - 1] + f[i];
}
int main()
{
    int T,l,r,cas=0;
    init();
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &l, &r);
        printf("Case #%d: %lld\n",++cas,sum[r] - sum[l - 1]);
    }
    return 0;
}

参考博客:
https://blog.csdn.net/fztsilly/article/details/107813922

posted @ 2020-08-06 10:24  xzx9  阅读(165)  评论(0编辑  收藏  举报