涂色

涂 色 涂色

题目链接:SSL 2124

题目

有一根长度为 1000000000 1000000000 1000000000的棍子,一开始涂成白色。
棍子上有刻度,左端点为 0 0 0,右端点 1000000000 1000000000 1000000000
由于某种原因这根棍子的某些部分被重新涂过了。
重新涂的颜色可能是黑色或着白色。
棍子总共被依次重新涂了 N N N次。
找出最后最长的白色段。

输入

1 1 1行一个数 N N N
接下来 N N N行表示一次涂色,格式如下:
a i   b i   c i ai\ bi\ ci ai bi ci
a i ai ai b i bi bi为整数, c i ci ci是字母 b b b w w w
表示把 a i ai ai b i bi bi之间那段涂成 c i ci ci色( w w w白色, b b b黑色)。

输出

一行,两个数 x x x y y y x x x如果有多个最长的段,输出 x x x最小的一个。

数据范围

1 &lt; = N &lt; = 5000 1&lt;=N&lt;=5000 1<=N<=5000
0 &lt; = a i &lt; = b i &lt; = 1000000000 0&lt;=ai&lt;=bi&lt;=1000000000 0<=ai<=bi<=1000000000

样例输入

4
1 999999997 b
40 300 w
300 634 w
43 47 b

样例输出

47 634

思路

这道题是一道离散化。
我们离散化之后,就求出最长的白色线段,然后就可以了。

代码

#include<cstdio>
#include<algorithm>
#define ll long long
#define max(x, y) (x) > (y) ? (x) : (y)

using namespace std;

ll n, a[3][5001], b[10001], k, ansl, ansr, l, r;
bool color[5001]; 
char c;S

int main() {
	scanf("%d", &n);//读入
	a[2][0] = 2147483647;//初始化
	for (int i = 1; i <= n; i++) {
		scanf("%d %d", &a[1][i], &a[2][i]);//读入
		getchar();//处理换行符
		c = getchar();//读入
		if (c == 'b') color[i] = 1;//是黑色
		b[++k] = a[1][i];//记录
		b[++k] = a[2][i];
	}
	
	sort (b + 1, b + k + 1);//离散化
	
	for (ll i = 1; i <= k; i++)
		for (ll j = n; j >= 0; j--)
			if (b[i - 1] >= a[1][j] && b[i] <= a[2][j]) {//是否在区间内
				if (color[j]) {//是否变成了黑色
					if (r - l > ansr - ansl) {//比答案值更大
						ansr = r;//更新
						ansl = l;
					}
					l = b[i];//更新范围
					r = b[i + 1];
				}
				if (b[i - 1] <= r) r = b[i];//更新最右值
				break;//找到了就退出
			}
	
	printf("%lld %lld", ansl, ansr);//输出
	
	return 0;
}
### NOJ 涂色问题的算法与实现 #### 问题解析 涂色问题是典型的动态规划或组合计数类题目。对于给定的网格结构以及特定约束条件下的涂色方式计算,通常可以通过状态转移的方式求解。 在本案例中提到两种不同的涂色场景: 1. **方格涂色游戏**:涉及如何通过合理的涂色策略使得每次都能成功消除一行[^1]。 2. **三行 n 列网格涂色问题**:要求使用三种颜色填充网格并满足相邻单元格的颜色不相同[^2]。 以下是针对第二种问题的具体解决方案及其代码实现。 --- #### 动态规划方法描述 定义 `dp[i][j]` 表示前 i 行已经完成涂色的情况下,第 i 行的状态为 j 的合法涂色方案总数。其中,每一行的状态可以用一个整数表示,该整数的每一位代表对应列的颜色编号(假设颜色分别为0, 1, 2)。因此,总共有 \(3^n\) 种可能的状态。 为了减少不必要的计算量,需预先筛选出所有符合条件的单行状态集合 S 和两行之间相互兼容的状态对 (s1,s2),即当 s1 是当前行的状态而 s2 是下一行的状态时,它们不会违反任何规则。 最终答案将是 dp[n][*] 中所有元素之和,因为最后一行可以处于任意一种有效状态之中。 时间复杂度主要取决于预处理阶构建S所需的时间O(3ⁿ)加上实际DP过程中的迭代次数O(|S|²×n)。 --- #### Python 实现代码 下面提供了一个基于上述思路编写的Python程序来解决此类型的涂色问题: ```python def count_ways(n): MOD = 10**9 + 7 # Generate all possible states for one row. def generate_states(): valid_states = [] colors = range(3) for state in product(colors, repeat=n): if all(state[i]!=state[i+1] for i in range(len(state)-1)): valid_states.append(tuple(state)) return valid_states from itertools import product # Precompute the list of valid single-row colorings and compatible pairs between rows. states = generate_states() m = len(states) compatibles = [[False]*m for _ in range(m)] for idx1,state1 in enumerate(states): for idx2,state2 in enumerate(states): if all(c1!=c2 for c1,c2 in zip(state1,state2)): compatibles[idx1][idx2]=True # Initialize DP table with first row possibilities. prev_dp=[int(all(s[0]!=s[-1]))%MOD for s in states] # Perform dynamic programming over subsequent rows. curr_dp=None for layer in range(1,n): curr_dp=[sum(prev_dp[k]for k in range(m)if compatibles[k][l]) % MOD for l in range(m)] prev_dp=curr_dp[:] result=sum(curr_dp)%MOD return result # Example usage: print(count_ways(4)) # Output depends on input size 'n' ``` --- #### 结果解释 这脚本接受参数 n ,返回的是按照指定规则能够形成的独特图案数量 mod \(1e9+7\). 它利用了笛卡尔积生成器创建候选集,并借助布尔矩阵记录哪些配对可行从而加速后续运算. 注意这里采用了滚动数组技巧优化空间消耗至 O(M), M 即为合法单一排列数目; 同样也采取模运算防止数值溢出影响准确性. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值