CSP202104-4 校门外的树

原题点我

DP好题

打眼一看,感觉是个dp,而我的dp很菜(其实不管什么都很菜),看到区间就想到区间dp,导致有一点思路,但是无法实现。实际上我们不关心中间的某一段的种树情况,只需要知道从第一个障碍物开始到最后一个障碍物结束的种树方案,因此只需要一维数组。
fi表示从第一个障碍物到第i个障碍物的总方案数,那么很容易写出fi=j=1i1fjcalc(i,j),其中calc(i,j)表示第i个障碍物到第j个障碍物之间的方案数。假设f1fi1都已经求出来,那么求fi就只需要求出calc(i,j)
现在我们设法写出calc函数。显然,对于中间没有障碍物的两个障碍物来说,他们之间的方案数就是两个障碍物之间距离的约数(不包括自己)的个数。举例: 设两个障碍物的坐标分别是aiai+1,那么calc(i+1,i)=sizeof(X),其中X表示ai+1ai的约数(不包括自己)所组成的集合。那么对于中间有障碍物的两个障碍物来说呢?因为在dp的过程中,在枚举左端点j时,右端点i是不动的,所以我们就以右端点为基准。显然,在集合X中的数都不能再作为现在的备选答案了,因为若选择这些数作为答案,则从右端点开始计算,必将在之前的左端点处种下一棵树,但实际上这是非法的操作。同样地,之前的两个障碍物之间的距离也不能作为备选答案。
具体来说,建立一个初始为空的集合Y,从j=i1开始枚举倒序枚举j,每次都找出aiaj的约数所组成的集合Zj,对于Zj中的每一个元素,检查它是否在集合Y中,若在集合Y中,则表明以这个元素作为间隔去种树会在某一个障碍物处种数,所以不能计入答案,若不在集合Y中,则可以计入答案,并将其插入集合Y中,处理完后,还要把aiaj也加入集合中。

初始状态: f1=1 最终状态: fn=?

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#define ll long long
using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 1e5 + 10;
const int m = 1e9 + 7;
int a[maxn];
vector<int> pr[maxm];
int n;
bool vis[maxm];

ll f[maxn];
ll calc(int p, int q);

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    
    for(int i = 1; i <= a[n]; i++)
        for(int j = 2 * i; j <= a[n]; j += i)
            pr[j].push_back(i);
    
    f[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        memset(vis, 0, sizeof(vis));
        for(int j = i - 1; j >= 1; j--)
            f[i] = f[j] % m * calc(i, j) % m + f[i] % m;
        
    }
    printf("%lld\n", f[n] % m);
    
}

ll calc(int p, int q)
{
    ll ret = 0;
    for(int t : pr[a[p] - a[q]])
        if(!vis[t])
        {
            ret = ret + 1 % m;
            vis[t] = true;
        }
    vis[a[p] - a[q]] = true;
    return ret % m;
}

总结

倒序枚举j是比较关键的操作,想到这一步的原因是两个相邻的障碍物之间的方案数比较容易计算,而之后扩展到不相邻的障碍物时,非法集合中的元素只增多不减少,比较容易维护。

posted @   Franky0705  阅读(117)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示