CCPC2024-girls D 优秀的拆分(LIS,数数)
CCPC2024-girls D 优秀的拆分(LIS,数数)
给一个排列 \(p\),求该排列元素不重复的 \(\max\{\text{LIS}+\text{LDS}\}\).
(具体地说是将该排列任意划分为两个子序列 A 与 B,求 \(\max\{\text{LIS(A)}+\text{LDS(B)}\}\),其中 \(\text{LIS(A)}\) 表示 A 的最长上升子序列的长度 ).
可以注意到对 \(p\) 任取一个 LIS 和一个 LDS,至多会有一个重合的元素.
因为答案上限是 LIS+LDS,所以答案只能为 LIS+LDS 或 LIS+LDS-1.
考虑什么情况下答案需要 -1: 若任取 LIS 和 LDS 必有一个重合的元素,则答案为 LIS+LDS-1.
去掉 LIS 再求 LDS 之类的想法并不好做. 可以把这个题转化成数数题():
求任取 LIS 和 LDS 的方案数 \(S=\text{SLIS}\times \text{SLDS}\)
其中 \(\text{SLIS}\) 表示 \(p\) 的 LIS 数量.
选定 \(a_k\),求在 \(a_k\) 处重合的一组 LIS 与 LDS 的组数 \(S_k=\text{LISg(k)}\times \text{LDSg(k)}\)
其中 \(\text{LIS(k)}\) 表示 \(p\) 的所有包含 \(a_k\) 的 LIS 数量.
若 \(S=\sum_{k=1}^{n}S_k\),则答案为 LIS+LDS-1,否则答案为 LIS+LDS.
因为需要做判等,所以想了一下 LIS 计数的量级. 如果把 \(n\) 排列 \(p\) 均分为 \(x\) 段,每一段都取连续的下降列,例如 321654987 这样,那么 LIS 数量应该是 \((\frac{n}{x})^x\). 求导,解得 \(x_0=\frac{n}{e}\),得上限 \(e^{\frac{n}{e}}\),还是指数级的. 因为题解没有提到,一开始以为量级是不会超过 i64 的()
虽然题解没有提到,目前看来可能得找个大质数当模数了.
如何做 LIS 计数?笨比 nqZ 昨天写了个俩 log 的做法.
实际上可以一 log,区间 f 和 g 的答案还是有结合律的.
转移:
Info operator + (Info a,Info b)
{
return (Info){max(a.f,b.f), ((a.f==b.f)?((a.g+b.g)%mod):(a.f>b.f?a.g:b.g)),min(a.l,b.l),max(a.r,b.r)};
}
LIS 和 LDS 各做两次,处理出 \(f1\),\(g1\),\(f2\),\(g2\),\(f3\),\(g3\),\(f4\),\(g4\)
两个 sum 值分别是:
struct Info
{
i64 f=0,g=0,l=0,r=0;
void apply(Tag t)
{
;
}
};
Info operator + (Info a,Info b)
{
return (Info){max(a.f,b.f), ((a.f==b.f)?((a.g+b.g)%mod):(a.f>b.f?a.g:b.g)),min(a.l,b.l),max(a.r,b.r)};
}
void R()
{
int n;
cin>>n;
vector<int> p(n);
for (int i=0;i<n;i++) cin>>p[i];
SGT<Info,Tag> sgt1(n),sgt2(n),sgt3(n),sgt4(n);
vector<int> f1(n),f2(n),f3(n),f4(n);
vector<i64> g1(n),g2(n),g3(n),g4(n);
int LIS=0,LDS=0;
for (int i=0,L,R;i<n;i++)
{
Info U=sgt1.rangeQuery(0,p[i]-1);
f1[i]=U.f+1;
g1[i]=U.g;
if (f1[i]==1) g1[i]=1;
sgt1.modify(p[i]-1,{f1[i],g1[i],p[i]-1,p[i]-1});
LIS=max(LIS,f1[i]);
}
i64 SLIS=0;
for (int i=0;i<n;i++) if (f1[i]==LIS) SLIS=(SLIS+g1[i])%mod;
// cout<<"LIS="<<LIS<<" SLIS="<<SLIS<<endl;
for (int i=n-1,L,R;i>=0;i--)
{
Info U=sgt4.rangeQuery(0,p[i]-1);
f4[i]=U.f+1;
g4[i]=U.g;
if (f4[i]==1) g4[i]=1;
sgt4.modify(p[i]-1,{f4[i],g4[i],p[i]-1,p[i]-1});
}
for (int i=0,L,R;i<n;i++)
{
Info U=sgt3.rangeQuery(p[i],n);
f3[i]=U.f+1;
g3[i]=U.g;
if (f3[i]==1) g3[i]=1;
sgt3.modify(p[i]-1,{f3[i],g3[i],p[i]-1,p[i]-1});
LDS=max(LDS,f3[i]);
}
for (int i=n-1,L,R;i>=0;i--)
{
Info U=sgt2.rangeQuery(p[i],n);
f2[i]=U.f+1;
g2[i]=U.g;
if (f2[i]==1) g2[i]=1;
sgt2.modify(p[i]-1,{f2[i],g2[i],p[i]-1,p[i]-1});
}
i64 SLDS=0;
for (int i=0;i<n;i++) if (f3[i]==LDS) SLDS=(SLDS+g3[i])%mod;
// cout<<"LDS="<<LDS<<" SLDS="<<SLDS<<endl;
i64 sum=0;
/*
cout<<"f1-----------"<<endl; for (int i=0;i<n;i++) cout<<f1[i]<<" "; cout<<endl;
cout<<"g1-----------"<<endl; for (int i=0;i<n;i++) cout<<g1[i]<<" "; cout<<endl;
cout<<"f2-----------"<<endl; for (int i=0;i<n;i++) cout<<f2[i]<<" "; cout<<endl;
cout<<"g2-----------"<<endl; for (int i=0;i<n;i++) cout<<g2[i]<<" "; cout<<endl;
cout<<"f3-----------"<<endl; for (int i=0;i<n;i++) cout<<f3[i]<<" "; cout<<endl;
cout<<"g3-----------"<<endl; for (int i=0;i<n;i++) cout<<g3[i]<<" "; cout<<endl;
cout<<"f4-----------"<<endl; for (int i=0;i<n;i++) cout<<f4[i]<<" "; cout<<endl;
cout<<"g4-----------"<<endl; for (int i=0;i<n;i++) cout<<g4[i]<<" "; cout<<endl;
*/
for (int i=0;i<n;i++)
{
if (f1[i]+f2[i]-1==LIS&&f3[i]+f4[i]-1==LDS)
{
sum=(sum+g1[i]*g3[i]%mod*g2[i]%mod*g4[i]%mod)%mod;
}
}
int ans=LIS+LDS;
if (sum==SLIS*SLDS%mod) ans--;
cout<<ans<<endl;
return;
}

浙公网安备 33010602011771号