牛客网NOIP赛前集训营-提高组(第三场)A-管道维修

A-管道维修

题目描述

在维修下水管道的过程中,发现一块n×m的易堵区域。为了方便表示,将易堵区域第 i i i行第 j j j列的格子命名为格子 ( i , j ) ( 1 ≤ i ≤ n , 1 ≤ j ≤ m ) (i,j)(1≤i≤n,1≤j≤m) (i,j)(1in,1jm)。每次维修下水道时,其中有些格子是堵塞状态,有些则是未堵塞状态。维修需要分步进行:所有与 n × m n×m n×m长方形四周边界相邻的格子或者与未被堵塞的格子相邻(四连通)的堵塞格子都可以在第1步内清理完毕。第k步过后,清理完毕的格子就变成未被堵塞的格子,这时与边界或者未堵塞的格子相邻的堵塞格子都会在第 k + 1 k+1 k+1步内被清理完毕。依此类推,直到所有格子都变成未堵塞的格子。现在下水道内的情况未知,格子 ( i , j ) (i,j) (i,j)堵塞的概率为 p ( i , j ) p(i,j) p(i,j)。不同格子之间堵塞的事件相互独立。现在求每个格子平均需要到第几步被清理完毕。一个格子如果一开始就是未堵塞的,算作在第 0 0 0步被清理完毕。

输入描述:

第一行两个个正整数 n n n m m m表示区域的大小。 ( 1 ≤ n , m ≤ 200 ) (1≤n,m≤200) (1n,m200) 接下来n行每行m个整数对 a , b a,b a,b表示格子被堵塞的概率是 a / b a/b a/b ( 0 ≤ a ≤ b , 1 ≤ b &lt; 1 0 9 + 7 ) (0≤a≤b,1≤b&lt;10^9+7) (0ab,1b<109+7)

输出描述:

n n n行每行 m m m个整数表示格子平均在第几步清理完毕。为了避免精度问题,如果平均在第 c / d c/d c/d步内被清理完毕,则输出 c ⋅ d − 1 ( m o d 1 0 9 + 7 ) c⋅d−1(mod10^9+7) cd1(mod109+7),其中 d − 1 d−1 d1表示 d d d关于 1 0 9 + 7 10^9+7 109+7的逆元,即 0 0 0 1 0 9 + 6 10^9+6 109+6以内唯一一个和 d d d相乘后模 1 0 9 + 7 10^9+7 109+7等于 1 1 1的整数。

示例1
输入

5 5
1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2
1 2 1 2 1 2 1 2 1 2

输出

500000004 500000004 500000004 500000004 500000004
500000004 781250006 781250006 781250006 500000004
500000004 781250006 665161138 781250006 500000004
500000004 781250006 781250006 781250006 500000004
500000004 500000004 500000004 500000004 500000004

说明

以左上的格子为例,如果这个格子是堵塞格子(发生概率为 1 / 2 1/2 1/2),由于它和边界相邻,一定可以在第 1 1 1轮就被清理完毕。如果它不是堵塞格子,按照定义在第 0 0 0轮清理完毕。所以平均它在第 1 / 2 1/2 1/2轮被清理完毕。 2 2 2的逆元是 500000004 500000004 500000004。其它与边界不相邻的格子有可能在第 2 2 2轮才被清理完毕,取决于它们旁边的格子是否是堵塞的。

示例2
输入

3 3
1 2 1 3 1 2
1 3 2 3 1 3
1 2 1 3 1 2

输出

500000004 333333336 500000004
333333336 82304528 333333336
500000004 333333336 500000004

Solution

对于每一个 ( i , j ) (i,j) (i,j)计算期望先考虑样例1
( 2 , 2 ) (2,2) (2,2)的计算方法 1 2 × 0 + 1 2 × 15 16 × 1 + 1 2 × 1 16 × 2 = 17 32 \frac{1}{2}\times 0+\frac{1}{2}\times \frac{15}{16}\times 1+\frac{1}{2}\times \frac{1}{16}\times 2=\frac{17}{32} 21×0+21×1615×1+21×161×2=3217
17 × 3 2 − 1 ≡ 17 × 3 2 1000000005 ≡ 781250006 ( m o d &ThinSpace;&ThinSpace; 1000000007 ) 17\times 32^{-1}\equiv 17 \times 32^{1000000005}\equiv 781250006(\mod1000000007) 17×32117×321000000005781250006(mod1000000007)
( 3 , 3 ) (3,3) (3,3)的计算方法也类似 1 2 × 0 + 1 2 × 15 16 × 1 + 1 2 × 1 16 × 255 256 × 2 + 1 2 × 1 16 × 1 256 × 3 \frac{1}{2}\times 0+\frac{1}{2}\times \frac{15}{16}\times 1+\frac{1}{2}\times\frac{1}{16}\times\frac{255}{256}\times 2+\frac{1}{2}\times\frac{1}{16}\times\frac{1}{256}\times3 21×0+21×1615×1+21×161×256255×2+21×161×2561×3(具体数值也没有算过)
可以发现一个规律:每层往外扩展都是分成两种情况
1.这层全是堵塞的(概率为 ∏ a b \prod\frac{a}{b} ba)
2.这层不是全部堵塞(概率为 1 − ∏ a b 1-\prod\frac{a}{b} 1ba)
其中第一种情况是可以继续扩展的
所以如果存在有一层 ∃ a = 0 \exist a=0 a=0,则 ∏ a b = 0 \prod\frac{a}{b}=0 ba=0可以直接跳出循环
后来维护每层的概率积有两种方法
1.暴力,时间复杂度 θ ( n 4 ) \theta(n^4) θ(n4)
2.前缀积,时间复杂度 θ ( n 3 ) \theta(n^3) θ(n3),当然这个前缀积是要斜着维护的,而且要维护两个方向
direction
这个前缀积还有坑!!!
如果有 0 0 0的情况就会出现 0 0 \frac{0}{0} 00的惨状,但是发现遇到 0 0 0可以直接跳出,于是又用同样的方法维护了一遍 0 0 0的个数,如果存在 0 0 0就结束。
至于分数的运算很麻烦的问题…dalao告诉我们可以直接使用逆元进行运算,不会有任何问题

Code(然而不知道哪出bug了,94分…)

#include <cstdio>
#include <algorithm>
#define N 205
#define MOD 1000000007

typedef long long LL;
using namespace std;

int ll[N][N], rr[N][N];//ll,rr是0的个数前缀和
LL lo[N][N], ro[N][N], val[N][N];//lo,ro是前缀积,val是一个点的概率的逆元

LL qui_pow(LL x, int y) {
	if (y == 1) return x;
	LL t = qui_pow(x, y / 2);
	if (y % 2 == 0) return t * t % MOD;
	else return t * t % MOD * x % MOD;
}

int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			LL a, b;
			scanf("%lld%lld", &a, &b);
			val[i][j] = a * qui_pow(b, MOD - 2) % MOD;
		}
	}
	for (int i = 0; i <= n + 1; ++i) {
		for (int j = 0; j <= n + 1; ++j) {
			if (i == 0 || j == 0) {
				lo[i][j] = ro[i][j] = 1;//不能出现lo,ro为零的情况
			}
		}
	}
	for (int i = 1; i <= n; ++i) {//前缀预处理
		for (int j = 1; j <= m; ++j) {
			if (val[i][j] == 0) {
				ll[i][j] = ll[i - 1][j - 1] + 1;
				rr[i][j] = rr[i - 1][j + 1] + 1;
			}
			else {
				ll[i][j] = ll[i - 1][j - 1];
				rr[i][j] = rr[i - 1][j + 1];
			}
			lo[i][j] = lo[i - 1][j - 1] * val[i][j] % MOD;
			ro[i][j] = ro[i - 1][j + 1] * val[i][j] % MOD;
			if (lo[i][j] == 0) lo[i][j] = 1;
			if (ro[i][j] == 0) ro[i][j] = 1;//不能出现lo,ro为零的情况
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			int p = min(min(i, j), min(n - i + 1, m - j + 1));//最大层数
			LL ans = 0, now = val[i][j];
			for (int k = 1; k <= p; ++k) {
				int cnt = ll[i + k - 1][j] - ll[i - 1][j - k]
						+ ll[i][j + k - 1] - ll[i - k][j - 1]
						+ rr[i - 1][j - k + 2] - rr[i - k + 1][j] 
						+ rr[i + k - 2][j + 1] - rr[i][j + k - 1];//0个数
				LL  pob = lo[i + k][j] * qui_pow(lo[i - 1][j - k - 1], MOD - 2) % MOD
						* lo[i][j + k] % MOD * qui_pow(lo[i - k - 1][j - 1], MOD - 2) % MOD
						* ro[i - 1][j - k + 1] % MOD * qui_pow(ro[i - k][j], MOD - 2) % MOD
						* ro[i + k - 1][j + 1] % MOD * qui_pow(ro[i][j + k], MOD - 2) % MOD;//概率的逆元
				if (cnt > 0) {//处理边界小问题,break
					ans = (ans + now * (k - 1)) % MOD;
					break;
				}
				if (k < p) ans = (ans + (MOD + 1 - pob) * now % MOD * k) % MOD;
				else ans = (ans + now * k) % MOD;//处理边界小问题同上
				now = pob * now % MOD;
			}
			printf("%lld", ans);
			if (j < m) putchar(' ');
			else putchar('\n');
		}
	}
	return 0;
}

蒟蒻只能码提高t1了qnq

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOIP(全国青少年信息学奥林匹克竞赛)是中国举办的一项顶尖竞赛,旨在选拔和培养青少年信息学人才。CSP(计算机科学与编程竞赛)是NOIP的初赛,包括提高和普及两个不同难度的竞赛。 从1995年到2021年,CSP提高复赛试题持续不断地推陈出新。试题的难度和内容与时俱进,反映了信息科技和计算机学科的发展趋势。 这些试题涵盖了计算机科学与编程的各个领域,如数据结构、算法设计与分析、图论、动态规划等。这些题目不仅要求考生熟悉编程语言,还需要考生具备分析问题、设计算法、优化程序的能力。因此,参加CSP的考生需要有扎实的计算机基础知识和编程技巧。 CSP试题的设计目标是培养学生的创新思维、动手能力和问题解决能力。试题往往是实际问题的抽象化,考生需要将问题拆解、建模,并设计出适用的算法和程序来解决。这种综合应用的能力培养能够提高学生的实践能力和创新能力,为他们今后的学习和工作打下坚实的基础。 此外,CSP试题还注重培养学生的团队合作精神和竞技意识。复赛试题通常要求考生在限定时间内完成,这要求考生在有限的时间内高效地协作和解决问题。 总之,NOIP CSP提高复赛试题的不断更新和提高,以及其注重培养学生的综合能力,使得参加这项竞赛的学生能够更好地理解和应用计算机科学知识,为他们日后的学习和发展打下良好的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值