ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P4229 - 某位歌姬的故事(DP)

2022-03-05 19:31:21  阅读:136  来源: 互联网

标签:le 洛谷 int MAXN DP P4229 mx dp MOD


洛谷题面传送门

首先将限制写成左开右闭区间的形式并离散化,下面默认 \(n\) 与 \(Q\) 同阶。

我们考虑设 \(mx_i\) 表示 \(i\) 最大能够取到的值,即 \(\min\limits_{l_j\le i\le r_j}w_j\)。那么对于一个 \(w_i=v\) 的位置,容易证明,必然存在 \(mx_j=v\) 且 \(l_i\le j\le r_i\) 满足 \(a_j=v\),因为对于 \(l_i\le j\le r_i\) 必然有 \(mx_j\le w_i\),并且最大值 \(w_i\) 肯定不能存在于 \(mx_j<w_i\) 的位置,因此必然存在一个 \(mx_j=w_i\) 且 \(j\in[l_i,r_i]\) 的位置,满足其值恰好等于 \(w_i\)。

因此我们考虑对每种 \(v\),将 \(mx_i=v\) 的位置 \(i\) 与 \(w_j=v\) 的限制 \(j\) 拎出来算一下方案数,然后用乘法原理乘起来就是答案,于是问题转化为,有 \(m\) 个关键位置 \(p_1,p_2,\cdots,p_m\),再给你 \(k\) 个限制 \([l_i,r_i]\),要求有多少种在这 \(m\) 个关键位置上填数的方案数,要求 \(a_{p_i}\le X\),且对于每个限制,\([l_i,r_i]\) 中至少有一个数等于 \(X\)。

到这里,问题就和远古时期做的一道题 P3600 随机数生成器 一样了,按照那题的套路,设 \(dp_i\) 表示当前最后一个取到 \(X\) 的数为 \(p_i\),枚举上一个数转移即可。理论上来说可以做到线性,不过我偷懒写了个 \(n^2\) 的做法,由于此题数据范围较小,\(n^2\) 做法也可以通过。

const int MAXN = 500;
const int MOD = 998244353;
const int INF = 0x3f3f3f3f;
int qpow(int x, int e) {
	int ret = 1;
	for (; e; e >>= 1, x = 1ll * x * x % MOD)
		if (e & 1) ret = 1ll * ret * x % MOD;
	return ret;
}
int n, m, A, key[MAXN * 2 + 5], uni[MAXN * 2 + 5], cnt, num;
struct event {int l, r, v;} q[MAXN + 5];
int mx[MAXN * 2 + 5], dp[MAXN * 2 + 5], ppw[MAXN * 2 + 5];
void clear() {
	memset(key, 0, sizeof(key)); memset(uni, 0, sizeof(uni));
	cnt = num = 0;
}
int calc(int val, vector<int> A, vector<int> B) {
	if (A.empty()) return 0; memset(dp, 0, sizeof(dp)); dp[0] = 1;
	int len = A.size(); A.insert(A.begin(), 0);
	for (int i = 1; i <= len; i++) ppw[i] = qpow(val - 1, uni[A[i] + 1] - uni[A[i]]);
	for (int i = 1; i <= len; i++) {
		int mx = 0, pw = (qpow(val, uni[A[i] + 1] - uni[A[i]]) - qpow(val - 1, uni[A[i] + 1] - uni[A[i]]) + MOD) % MOD;
		for (int id : B) if (q[id].r <= A[i]) chkmax(mx, q[id].l);
		for (int j = i - 1; A[j] >= mx && j >= 0; j--) {
			dp[i] = (dp[i] + 1ll * dp[j] * pw) % MOD;
			pw = 1ll * pw * ppw[j] % MOD;
		}
//		printf("dp[%d] = %d %d\n", i, dp[i], mx);
	}
	int res = 0;
	for (int i = 0; i <= len; i++) {
		bool flg = 1;
		for (int id : B) if (q[id].l > A[i]) {flg = 0; break;}
		if (flg) {
			int pw = 1;
			for (int j = i + 1; j <= len; j++) pw = 1ll * pw * ppw[j] % MOD;
			res = (res + 1ll * dp[i] * pw) % MOD;
		}
	}
//	printf("! %d %d\n", val, res);
	return res;
}
void solve() {
	scanf("%d%d%d", &n, &m, &A); clear(); set<int> st;
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%d", &q[i].l, &q[i].r, &q[i].v);
		q[i].r++; key[++cnt] = q[i].l; key[++cnt] = q[i].r;
		st.insert(q[i].v);
	}
	sort(key + 1, key + cnt + 1);
	for (int i = 1; i <= cnt; i++) if (key[i] != key[i - 1])
		uni[++num] = key[i];
	uni[num + 1] = n + 1;
	for (int i = 1; i <= m; i++) {
		q[i].l = lower_bound(uni + 1, uni + num + 1, q[i].l) - uni;
		q[i].r = lower_bound(uni + 1, uni + num + 1, q[i].r) - uni;
	}
	memset(mx, 63, sizeof(mx));
	for (int i = 1; i <= m; i++) for (int j = q[i].l; j < q[i].r; j++)
		chkmin(mx[j], q[i].v);
//	for (int i = 1; i <= num; i++) printf("%d%c", mx[i], " \n"[i == num]);
	int sum = 0, prd;
	for (int i = 1; i <= num; i++) if (mx[i] != INF)
		sum += uni[i + 1] - uni[i];
	prd = qpow(A, n - sum);
	for (int val : st) {
		vector<int> pts, eves;
		for (int i = 1; i <= num; i++) if (mx[i] == val) pts.pb(i);
		for (int i = 1; i <= m; i++) if (q[i].v == val) eves.pb(i);
		prd = 1ll * prd * calc(val, pts, eves) % MOD;
	}
	printf("%d\n", prd);
}
int main() {
	int qu; scanf("%d", &qu); while (qu--) solve();
	return 0;
}
/*
1
7 5 7
5 7 7
4 6 7
2 4 5
3 5 5
1 3 5
*/

标签:le,洛谷,int,MAXN,DP,P4229,mx,dp,MOD
来源: https://www.cnblogs.com/ET2006/p/luogu-P4229.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有