「清华集训2017」某位歌姬的故事
「清华集训2017」某位歌姬的故事
解题思路:
首先对于覆盖一个位置的所有限制,只需要取最小的那个即可,然后所有限制的位置都不交了,分别计算方案数相乘即可。
那么问题就转化为若干个位置可以放黑白两种颜色的球,要求每一个限制区间里面必须有一个黑球,求方案数。其中一个白球有 \(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;
}