0%

2025“钉耙编程”中国大学生算法设计暑期联赛(3)(2025杭电多校 3)——1009线段染色

1009线段染色

2025“钉耙编程”中国大学生算法设计暑期联赛(3)

https://acm.hdu.edu.cn/contest/problem?cid=1174&pid=1009

https://vjudge.net/problem/HDU-8011

又是沟槽的概率题目。

感觉不是我能碰瓷的题目,之后有兴趣了再来看吧。

https://grok.com/chat/dc6a06d2-50d6-4bb8-a88b-87a1c553307d

题目大意

题意简述

在一个长度为 nn 的数轴上(包含整点 1n1 \sim n),给出了 mm 条线段,第 ii 条线段覆盖区间 [li,ri][l_i, r_i]

针对数轴上的每个整点 ii,进行一次独立的染色操作,染色的成功率为 pi=ai10p_i = \frac{a_i}{10}

定义一条线段被染色,当且仅当该线段覆盖的整点中至少有一个被染色。

所有给定的 mm 条线段都被染色的概率。

输入格式

第一行包含一个整数 tt,表示测试数据组数。

对于每组数据:

  1. 第一行两个整数 n,mn, m,分别表示数轴长度和线段数量。

  2. 第二行 nn 个整数 a1,a2,,ana_1, a_2, \dots, a_n,表示每个点的染色概率参数(pi=ai/10p_i = a_i/10)。

  3. 接下来 mm 行,每行两个整数 li,ril_i, r_i,表示一条线段的左右端点。

输出格式

输出一个整数,表示概率对 109+710^9+7 取模后的结果。

数据范围

  • 1t5×1041 \le t \le 5 \times 10^4

  • 1n2×105,0m2×1051 \le n \le 2 \times 10^5, 0 \le m \le 2 \times 10^5

  • n,m2.5×106\sum n, \sum m \le 2.5 \times 10^6

  • 0ai100 \le a_i \le 10

样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
6
4 2
5 5 5 5
2 3
3 4
4 2
5 5 5 5
2 2
3 4
1 0
3
4 1
0 2 3 4
2 4
4 2
5 0 5 5
1 3
2 4
4 3
1 1 1 0
2 4
3 4
4 4

样例输出

1
2
3
4
5
6
625000005
375000003
1
48000001
625000005
0

样例解释

第一组数据:

  • n=4n=4,所有点染色概率均为 0.50.5

  • 线段为 [2,3][2, 3][3,4][3, 4]

  • 要使两条线段都被染色,需满足:(点2被染 或 点3被染) 且 (点3被染 或 点4被染)。

  • 情况分类:

    1. 点3被染(概率 0.50.5):此时两条线段都已满足条件。
    2. 点3未被染(概率 0.50.5):此时必须点2被染(概率 0.50.5)且点4被染(概率 0.50.5),概率为 0.5×0.5×0.5=0.1250.5 \times 0.5 \times 0.5 = 0.125
  • 总概率 =0.5+0.125=0.625=58= 0.5 + 0.125 = 0.625 = \frac{5}{8}

  • 58(mod109+7)=625000005\frac{5}{8} \pmod{10^9+7} = 625000005

第二组数据:

  • 线段为 [2,2][2, 2][3,4][3, 4]

  • 线段1仅包含点2,必须点2被染(概率 0.50.5)。

  • 线段2包含点3, 4,需至少一个被染,概率为 1(10.5)×(10.5)=0.751 - (1-0.5)\times(1-0.5) = 0.75

  • 两者独立,总概率 =0.5×0.75=0.375=38= 0.5 \times 0.75 = 0.375 = \frac{3}{8}

思路讲解

我们重新回来看这道题目啊,重新回来看一下这道题目。

这 AI 提示二搁这乱写的,这数轴上的每一个点都是染色点,哪来的不染色点啊?那属于搞笑来了,卧槽。

OK,我大概看懂了这个 AI 提示3了。这 AI 提示2属于是哈哈哈省略的有些过多了。啊,如果你要看 AI 提示的话,可以直接看这个 AI 提示3。嗯。

image

应该是如上图这个意思啊,我们先尝试一下能不能实现一下。因为这个转移合法性是具有单调性的。就是说,如果说这个 LR 不符合要求的话,那么更小的 L 是更加不可能符合要求的。那么这个还是非常容易就可以找到的。

啊,然后你按照这个思路写了一个 DP 程序以后,现在问题就是答案到底是什么?我们会发现答案不是 DP[N] 啊,答案不是 DP[N] 那怎么答案从何而来?答案是什么?现在的问题是这个。

我们最大的问题是少考虑了虚拟起点0。说白了,它可以从 0 转移过来。还有一个地方就是它转移过来的中间那一段,它不能够被染色。因此需要乘上一个不被染色因数。说白了就是计算一下中间那一段它的这个乘积嘛。

dpi=pi×j=F(i)i1(dpj×k=j+1i1qk)dp_i = p_i \times \sum_{j=F(i)}^{i-1} (dp_j \times \prod_{k=j+1}^{i-1} q_k)

后面的这一坨乘积其实不好求啊,不是很好求,因为对于每一个 DP【 j 】来说,它的这个乘积的项数是不一样的。哎,不过我们可以采用类似于维护区间和区间修改的树状数组一样。这个可能说的有点抽象。

我们使用 iPad 画图来说明一下我们的这个意思。

image

说白了就是在线段树中的 j 存储不同的逆元值,存储的 DP j 乘以不同的逆元值,进而得到乘以相同的值,达到乘以不同值的这个效果。觉得我这个图还是画的比较清楚的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
vector<ll> pre_mul(N+2,1);
for (int i=1;i<=N;++i) {
ll l=0,r=i-1;
while (l<r) {
ll mid=l+r>>1;
if (check(mid,i)) {
r=mid;
}else {
l=mid+1;
}
}
// 比 EP 还小的话,那么这个 L 所能够得到的值,它一定是一个0。和 EP 相等是没事的。
// 因为说白了,我们是求一个后缀和嘛。如果这个点必定被染色,那么在其之前的点是不可能和后面的 DP 不重合的。
l=max(l,ep);
ll res=tr.query(1,l,i-1).sum;
res*=P[i]*inv10%mod;
res%=mod;
res*=pre_mul[i-1];
res%=mod;
if (i>=mxL) {
// 这里是,就是说明这个点以后的所有点必须都是是未染色的。这样子可以保证不同情况之间,它们的概率是没有交集的。
ans+=res*qsuf[i+1];
ans%=mod;
}
pre_mul[i]=pre_mul[i-1]*(10-P[i])%mod*inv10%mod;
if (pre_mul[i]==0) {
pre_mul[i]=1;
ep=i;
}
tr.assign(1,i,{0,0,res*binpow(pre_mul[i],mod-2)%mod});
}

AC 代码

AC
https://acm.hdu.edu.cn/contest/view-code?cid=1174&rid=28065

https://vjudge.net/solution/67894251