202104-4校门外的树

简介: 202104-4校门外的树

本题链接 校门外的树

本博客给出本题截图

2.png

C++

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 1010, M = 100010, MOD = 1e9 + 7;
int n;
int a[N];
int f[N];
vector<int> q[M];
bool st[M];
int main()
{
    for (int i = 1; i < M; i ++ )
        for (int j = i * 2; j < M; j += i)
            q[j].push_back(i);
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    f[0] = 1;
    for (int i = 1; i < n; i ++ )
    {
        memset(st, false, sizeof st);
        for (int j = i - 1; j >= 0; j -- )
        {
            int d = a[i] - a[j], cnt = 0;
            for (int k: q[d])
                if (!st[k])
                {
                    cnt ++ ;
                    st[k] = true;
                }
            st[d] = true;
            f[i] = (f[i] + (LL)f[j] * cnt) % MOD;
        }
    }
    printf("%d\n", f[n - 1]);
    return 0;
}

总结

典型的 dp + 约数,注意预处理


超级长的题干抽象出来之后该问题为:对于一个起始点为 a[1],终点为 a[n] 的这么一条线段上,你可以选择若干个点,比如我们选择了两个点 a[k] 和 a[j],其中 k < j,那么我们就把这个线段分成了三段,分别为 a[1] ~ a[k],a[k] ~ a[j],a[j] ~ a[n],那么对于这么三段,每一段我们都可以把它进行等分,即存在一个点 t,使得 a[1] ~ t 的长度等于 t ~ a[k],(这是二等分,当然你也可以继续等分下去,当然这里必须保证是约数),并且 t 这个点不可以和 a[s],s ∈ (1, k) 重合,问满足这样约数条件有多少种情况是符合题意的


显然是一道 dp 问题,首先我们需要预处理约数,因为后续涉及到等分的操作,避免后期重复运算直接把范围内的约数都计算出来,放入到 q 中;然后去考虑需要几维的转移,实在不知道几维的话不妨从一维开始试,设 f[i] 表示的是前 i 个障碍点的所有方案,那么显然有初始化 f[0] = 1,然后状态转移:f[i] 可以从 f[0] ~ f[i - 1] 的状态中进行转移,假设 j ∈ [0, i),那么转移过程就变成了前 j 个点的方案数再乘上 a[j] ~ a[i] 这么一段可以划分成的个数,最后的 f[i] 就是对所有的情况求和(注意取模)


本题重中之重还在于 st 数组的使用,因为是要求和的原因,所以我们在不漏的前提下必须加入不重,那么对于 a[i] 而言,我们是从后往前进行遍历的,遍历的过程中,我们需要记录 k 这个长度是否是被用过的,如果用过,我们需要直接 continue,因为对于同一个 a[i] 而言如果我们在 a[r] 时是用过 k 的话,那么我们再次把每份分成长度为 k 的时候,比如此时是 a[l],那么我们 a[l] ~ a[i] 这段一定有一个划分点是 a[r],但是我们题目要求不可以有这种情况,故我们开一个 st 数组,每一个 a[i] 在进行状态转移的时候我们都需要清空一下,其作用就是记录分成长度为 k,这个长度是否被用过,如果没有用过,就让 cnt ++, st[k] = true;,最后记得要让st[a[i] - a[j]] = true;


目录
相关文章
|
6月前
|
IDE Java C#
C#初相识
C#初相识
52 0
|
5月前
|
C++
【洛谷 P1047】[NOIP2005 普及组] 校门外的树 题解(位集合)
**NOIP2005普及组问题:**给定长度为$l$的马路,上面等距种植着树,需移除位于建造地铁区域的树。输入包含马路长度和区域数,以及各区域起止点,输出移树后剩余树的数量。样例输入:$l=500$, $m=3$,输出:$298$。$20\%$数据无区域重合,$1 \leq l \leq 10^4$,$1 \leq m \leq 100$。解决方案利用位集合(bitset)表示树的状态,遍历区域将树设为0,最后统计1的数量。AC代码使用C++实现。
27 0
|
算法 Android开发 C++
LeetCode 周赛上分之旅 #49 再探内向基环树
学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode 周赛的解题报告,一起体会上分之旅。
90 1
|
6月前
DongDong认亲戚 - 并查集
DongDong认亲戚 - 并查集
20 0
|
6月前
校门外的树
校门外的树
21 0
|
算法
回溯算法——我欲修仙(功法篇)
回溯算法——我欲修仙(功法篇)
102 0
|
算法 搜索推荐 C语言
堆排序——我欲修仙(功法篇)
堆排序——我欲修仙(功法篇)
120 0
堆排序——我欲修仙(功法篇)
|
算法 C语言
二分查找——我欲修仙(功法篇)
二分查找——我欲修仙(功法篇)
85 0
洛谷P1047-校门外的树(模拟)
洛谷P1047-校门外的树(模拟)