「清華集訓2017」某位歌姬的故事

「清華集訓2017」某位歌姬的故事

[我永遠喜歡 IA].pngc++

解題思路git

首先對於覆蓋一個位置的全部限制,只須要取最小的那個便可,而後全部限制的位置都不交了,分別計算方案數相乘便可。spa

那麼問題就轉化爲若干個位置能夠放黑白兩種顏色的球,要求每個限制區間裏面必須有一個黑球,求方案數。其中一個白球有 $m_i-1$ 種方案。code

假設對第 $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)$ 。get

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;
}
相關文章
相關標籤/搜索