题意要求:我们要求出最大价值的四维上升序列,且统计最大价值四维上升序列的数量。
这显然是一道dp,那怎么转移呢?
当 xi<xj && yi<yj && zi<zj && ki<kj 时, dp[j] = max(dp[i] + val[j],dp[j]);这样最大价值就可以转移出来了,至于数量我们可以将dp开成pair,第一维转移价值,第二维统计数量。
那么我们该如何遍历转移呢?
我们会发现他转移的条件显然是一个四维偏序,我们可以通过套两次cdq来解决
注意:第四维存在树状数组中所以需要离散化,dp转移需要cdq强制左中右转移。
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
#define edl '\n'
const int N = 1e6 + 10;
const int M = 1e3 + 10;
const ll mod = 998244353;
ll n,m,q;
string s;
struct QWQ
{
ll x,y,z,k,sum,id;
bool ck;
}a[N],b[N],c[N];
bool cmp(QWQ A,QWQ B)
{
if(A.x != B.x) return A.x < B.x;
if(A.y != B.y) return A.y < B.y;
if(A.z != B.z) return A.z < B.z;
if(A.k != B.k) return A.k < B.k;
}
bool cmp1(QWQ A,QWQ B)
{
if(A.y != B.y) return A.y < B.y;
if(A.z != B.z) return A.z < B.z;
if(A.k != B.k) return A.k < B.k;
if(A.x != B.x) return A.x < B.x;
}
bool cmp2(QWQ A,QWQ B)
{
if(A.z != B.z) return A.z < B.z;
if(A.k != B.k) return A.k < B.k;
if(A.x != B.x) return A.x < B.x;
if(A.y != B.y) return A.y < B.y;
}
template <typename T>
struct Fenwick {
int n;
std::vector<T> a;
Fenwick(int n_ = 0) {
init(n_);
}
void init(int n_) {
n = n_;
a.assign(n, T{});
}
void add(int x, T &v) {
v.second %= mod;
for (int i = x + 1; i <= n; i += i & -i) {
if(a[i - 1].first == v.first)
{
a[i - 1].second += v.second;
a[i - 1].second %= mod;
}
if(v.first > a[i - 1].first) a[i - 1] = v;
}
}
//[0,x)
T sum(int x) {
T ans{};
for (int i = x; i > 0; i -= i & -i) {
if(a[i - 1].first == ans.first)
{
ans.second += a[i - 1].second;
ans.second %= mod;
}
if(a[i - 1].first > ans.first) ans = a[i - 1];
}
return ans;
}
//左闭右开
void clear(int x) {
for (int i = x + 1; i <= n; i += i & -i) {
a[i - 1].first = a[i - 1].second = 0;
}
}
};
Fenwick<pair<ll,ll>>f(N);
pair<ll,ll> dp[80001];
ll sum;
void cdq1(int l,int r)
{
if(l == r) return;
int mid = (l + r) >> 1;
cdq1(l,mid);
for(int i = l; i <= r; i ++ ) c[i] = b[i];
sort(c + l,c + mid + 1,cmp2);
sort(c + mid + 1,c + r + 1,cmp2);
int i = l;
int j = mid + 1;
while(j <= r)
{
if(c[j].ck)
{
++j;
continue;
}
else
{
while(i <= mid && c[i].z <= c[j].z)
{
if(c[i].ck) f.add(c[i].k,dp[c[i].id]);
++i;
}
}
pair<ll,ll> temp = f.sum(c[j].k + 1);
temp.first += c[j].sum;
if(temp.first == dp[c[j].id].first) dp[c[j].id].second=(dp[c[j].id].second+temp.second)%mod;
if(temp.first > dp[c[j].id].first) dp[c[j].id]=temp;
sum = max(sum,dp[c[j].id].first);
++j;
}
for(j = l; j < i; j ++ ) if(c[j].ck) f.clear(c[j].k);
cdq1(mid + 1,r);
}
void cdq(int l,int r)
{
if(l == r) return;
int mid = (l + r) >> 1;
cdq(l,mid);
for(int i = l; i <= r; i ++ ) b[i] = a[i];
for(int i = l; i <= mid; i ++ ) b[i].ck = 1;
sort(b + l,b + r + 1,cmp1);
cdq1(l,r);
cdq(mid + 1,r);
}
ll OK[N];
ll cnt1,cnt2;
int find(ll x) { return lower_bound(OK + 1, OK + 1 + cnt2, x) - OK; }
void solve()
{
cin >> n >> m;
for(int i = 1; i <= n; i ++ ) cin >> a[i].x >> a[i].y >> a[i].z >> a[i].k >> a[i].sum;
sort(a + 1, a + n + 1,cmp);
int nn = 0;
for(int i = 1; i <= n; i ++ )
{
if(a[i].x == a[nn].x && a[i].y == a[nn].y && a[i].z == a[nn].z && a[i].k == a[nn].k) a[nn].sum += a[i].sum;
else
{
a[++nn] = a[i];
a[nn].id = nn;
}
}
for(int i = 1; i <= nn; i ++ )
{
OK[++cnt1] = a[i].k;
OK[++cnt1] = a[i].k + 1;
dp[i].second = 1;
dp[i].first = a[i].sum;
}
sort(OK + 1, OK + 1 + cnt1);
for (int i = 1; i <= cnt1; i++)
if (i == 1 || OK[i - 1] < OK[i])
OK[++cnt2] = OK[i];
for(int i = 1; i <= nn; i ++ )
{
a[i].k = find(a[i].k);
}
cdq(1,nn);
cout << sum << edl;
ll ok = 0;
for(int i = 1; i <= nn; i ++ )
{
if(dp[i].first == sum)
{
ok += dp[i].second;
ok %= mod;
}
}
cout << ok << edl;
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
// cin >> t;
while(t -- ) solve();
return 0;
}