【解题报告】JOISC 2019 Day3
咦,Day 2 怎么消失了
咦,Day 2 怎么消失了
题意:
由于洛谷目前的中文题面过于简洁,导致看完中文题面之后本题就已经解决了一半,所以我来简单翻译一下英文题面。
有
个人,第 个人初始的时候手上有物品 。
他们之间可以交换物品,每个人恰好拿到一个物品。而每个人有对物品的偏好,第个人的偏好用排列 来表示。第 个人相较物品 更喜欢物品 ,当且仅当在排列 中 在 之前。
对于一个物品交换的排列,表示第 个物品最后到了 的手上。对于一个非空的,人的子集 ,如果子集内部的人,使用子集内所有人初始手上的物品进行交换,可以达到以下结果:
- 不存在一个人
,在子集内交换后得到物品 ,且第 个人比起 更喜欢 。 - 至少存在一个人
,在子集内交换后得到物品 ,且第 个人比起 更喜欢 。 则称这样一个子集
是“不稳定”的。一个物品交换的排列 是“稳定”的,当且仅当不存在一个“不稳定”的子集。
现给出一个物品交换的排列,求有多少种 使得 是“稳定”的。
(可以证明,对于一组,恰好存在一个 是“稳定”的) 。
题目链接:P4229 某位歌姬的故事
题意:
计数长度为
的序列 ,满足 ,且满足 个限制,第 个限制形如: 。
。
将序列按照
设
对于一个限制
于是枚举
则问题转变为:
计数长度为
的序列 ,满足 ,且满足若干限制,第 个限制形如: 中存在一个元素顶到 的上界。
显然有:设
需要注意的是,需要特殊判断没有被覆盖到的位置,他们可以在
时间复杂度
//Code By CXY07
#include<bits/stdc++.h>
using namespace std;
//#define FILE
#define int long long
#define file(FILENAME) freopen(FILENAME".in", "r", stdin), freopen(FILENAME".out", "w", stdout)
#define randint(l, r) (rand() % ((r) - (l) + 1) + (l))
#define LINE() cout << "LINE = " << __LINE__ << endl
#define debug(x) cout << #x << " = " << x << endl
#define abs(x) ((x) < 0 ? (-(x)) : (x))
#define inv(x) qpow((x), mod - 2)
#define lowbit(x) ((x) & (-(x)))
#define ull unsigned long long
#define pii pair<int, int>
#define LL long long
#define mp make_pair
#define pb push_back
#define scd second
#define vec vector
#define fst first
#define endl '\n'
const int MAXN = 1010;
const int INF = 2e9;
const double eps = 1e-6;
const double PI = acos(-1);
//const int mod = 1e9 + 7;
const int mod = 998244353;
//const int G = 3;
//const int base = 131;
int T, n, Q, A, Ans = 1, N;
int L[MAXN], R[MAXN], m[MAXN], p[MAXN];
int dp[MAXN][MAXN], mx[MAXN], lim[MAXN];
int idx[MAXN], idxc;
vec<int> v;
vec<pii> opt;
template<typename T> inline bool read(T &a) {
a = 0; char c = getchar(); int f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') {a = a * 10 + (c ^ 48); c = getchar();}
return a *= f, true;
}
template<typename A, typename ...B>
inline bool read(A &x, B &...y) {return read(x) && read(y...);}
int qpow(int x, int b) {
int res = 1;
for(; b; b >>= 1, (x *= x) %= mod) if(b & 1) (res *= x) %= mod;
return res;
}
int Getid(int x) {
return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}
int siz(int x) { assert(x < v.size()); return v[x] - v[x - 1]; }
int exist(int m, int s) {
return (qpow(m, s) - qpow(m - 1, s) + mod) % mod;
}
bool cmp(int x, int y) { return m[x] < m[y]; }
void modadd(int &x, int y) {
x += y;
if(x >= mod) x -= mod;
}
void clear() {
memset(mx, 0x3f, sizeof mx);
v.clear(); opt.clear(); Ans = 1;
}
int calc(int m, int l, int r) {
int res = 0; idxc = 0, dp[0][0] = 1;
for(int i = 1; i <= N; ++i) if(mx[i] == m) idx[++idxc] = i;
for(int i = l, L1, R1; i <= r; ++i) {
L1 = *lower_bound(idx + 1, idx + idxc + 1, L[p[i]]);
R1 = *(lower_bound(idx + 1, idx + idxc + 1, R[p[i]]) - 1);
lim[R1] = max(lim[R1], L1);
}
for(int i = 1; i <= N; ++i) lim[i] = max(lim[i], lim[i - 1]);
for(int i = 1; i <= idxc; ++i) {
for(int j = 0; j < idx[i]; ++j) {
(dp[i][idx[i]] += dp[i - 1][j] * exist(m, siz(idx[i]))) %= mod;
if(lim[idx[i]] <= j) (dp[i][j] = dp[i - 1][j] * qpow(m - 1, siz(idx[i]))) %= mod;
}
}
for(int i = 1; i <= idx[idxc]; ++i) modadd(res, dp[idxc][i]);
for(int i = 0; i <= N; ++i) lim[i] = 0;
for(int i = 1; i <= idxc; ++i)
for(int j = 0; j <= idx[i]; ++j) dp[i][j] = 0;
return res;
}
void solve() {
clear(); read(n), read(Q), read(A);
for(int i = 1; i <= Q; ++i) {
read(L[i]), read(R[i]), read(m[i]); R[i]++;
opt.pb(mp(L[i], 1)), opt.pb(mp(R[i], -1));
v.pb(L[i]), v.pb(R[i]), p[i] = i;
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end()); N = v.size();
for(int i = 1; i <= Q; ++i) {
L[i] = Getid(L[i]), R[i] = Getid(R[i]);
for(int j = L[i]; j < R[i]; ++j) mx[j] = min(mx[j], m[i]);
}
sort(p + 1, p + Q + 1, cmp);
for(int l = 1, r; l <= Q; l = r + 1) {
r = l;
while(r < Q && m[p[r + 1]] == m[p[l]]) r++;
Ans = Ans * calc(m[p[l]], l, r) % mod;
}
sort(opt.begin(), opt.end()); int cur = 0, pre = 1;
for(int l = 0, r; l < opt.size(); l = r + 1) {
if(!cur) Ans = Ans * qpow(A, opt[l].fst - pre) % mod;
r = l; cur += opt[l].scd;
while(r + 1 < opt.size() && opt[r + 1].fst == opt[l].fst) cur += opt[++r].scd;
pre = opt[l].fst;
}
Ans = Ans * qpow(A, n - pre + 1) % mod;
printf("%lld\n", Ans);
}
signed main () {
#ifdef FILE
freopen("P4229.in", "r", stdin);
freopen("P4229.out", "w", stdout);
#endif
read(T);
while(T--) solve();
return 0;
}