「清华集训2017」某位歌姬的故事

点点圈 提交于 2020-04-28 12:18:00

「清华集训2017」某位歌姬的故事

[我永远喜欢 IA].png

解题思路

首先对于覆盖一个位置的所有限制,只需要取最小的那个即可,然后所有限制的位置都不交了,分别计算方案数相乘即可。

那么问题就转化为若干个位置可以放黑白两种颜色的球,要求每一个限制区间里面必须有一个黑球,求方案数。其中一个白球有 $m_i-1$ 种方案。

假设对第 $k$ 种限制计算,令 $dp(i,j)$ 为前 $i$ 个位置最后一个黑球放在 $j$ 的方案数,维护一下每一个位置对应的限制最左边的黑球可以放在哪里,记为 $lim[i]$ 。 $$ dp(i,j)=dp(i-1,j)\times (m_k-1)^{size_i} \ (lim[i]\leq j < i)\ dp(i,i)=\sum dp(i-1,j)\times(m_k^{sizei}-(m_k-1)^{size_i}) $$ 复杂度 $\mathcal O(Tn^2)$ 。

code

/*program by mangoyang*/ 
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define int ll
const int N = 2005, mod = 998244353;
inline int Pow(int a, int b){
	int ans = 1;
	for(; b; b >>= 1, a = a * a % mod)
		if(b & 1) ans = ans * a % mod;
	return ans;
}
set<int> st;
int n, q, A, l[N], r[N], w[N], s[N], t[N], dp[N][N], mn[N], mx[N], len, total_data;
inline int calc(int now){
	int tot = 0;
	for(int i = 1; i <= len; i++) if(mn[i] == now) t[++tot] = i;
	if(!tot) return -1;
	for(int i = 1; i <= tot; i++) mx[i] = 0;
	for(int i = 1; i <= q; i++) if(w[i] == now){
		int L = lower_bound(t + 1, t + tot + 1, l[i]) - t;
		int R = lower_bound(t + 1, t + tot + 1, r[i]) - t - 1;
		mx[R] = max(mx[R], L);
	}
	dp[0][0] = 1;
	for(int i = 1; i <= tot; i++){
		dp[i][i] = 0;
		int choose0 = Pow(now - 1, s[t[i]+1] - s[t[i]]);
		int choose1 = Pow(now, s[t[i]+1] - s[t[i]]);
		for(int j = 0; j < i; j++){
			if(j >= mx[i]) dp[i][j] = dp[i-1][j] * choose0 % mod; else dp[i][j] = 0;
			dp[i][i] = (dp[i][i] + dp[i-1][j] * ((choose1 + mod - choose0) % mod) % mod) % mod;
		}
	}
	int res = 0;
	for(int i = 0; i <= tot; i++) res = (res + dp[tot][i]) % mod;
	return res;
}
inline void solve(){
	st.clear(), read(n), read(q), read(A), s[len=1] = 1;
	for(int i = 1; i <= q; i++){
		read(l[i]), read(r[i]), read(w[i]), r[i]++;
		s[++len] = l[i], s[++len] = r[i], st.insert(w[i]);
	}
	s[++len] = n + 1, sort(s + 1, s + len + 1);
	len = unique(s + 1, s + len + 1) - s - 1;
	for(int i = 1; i <= len; i++) mn[i] = A + 1;
	for(int i = 1; i <= q; i++){
		l[i] = lower_bound(s + 1, s + len + 1, l[i]) - s;
		r[i] = lower_bound(s + 1, s + len + 1, r[i]) - s;
		for(int j = l[i]; j < r[i]; j++) mn[j] = min(mn[j], w[i]);
	}
	int res = 1, x;
	static set<int>::iterator it;
	for(it = st.begin(); it != st.end(); it++){
		if(~(x = calc(*it))) res = res * x % mod; 
		else return (void) (puts("0"));
	}
	for(int i = 1; i < len; i++) 
		if(mn[i] == A + 1) res = res * Pow(A, s[i+1] - s[i]) % mod;
	printf("%lld\n", res);
}
signed main(){
	int T; read(T); while(T--) solve();
	return 0;
}	
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!