题意:
求每个数在最长上升子序列中出现的概率。
题解:
首先求出最长上升子序列有那些数,通过二分+dp可以求出最长上升子序列中每个数,是出现在哪个位置上,然后出现在同一位置的数的值一定的从大到小的。所以对于位置 假设你当前选的是x[i][j]的后一个位置i+1可以选择的数一定是靠前出现的,因为后面出现的数可能比x[i][j]要小。根据此性质从后往前dp算可以填x[i][j]上去的概率,再从前往后dp可以填x[i][j]上去的概率,相乘后就是答案。复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MX = 5e5+7;
const int mod = 998244353;
const int Sqr = sqrt(MX);
LL qpow(LL a, LL n){
LL ret = 1;
while(n > 0){
if(n&1) ret = ret*a%mod;
a = a*a%mod;
n >>= 1;
}
return ret;
}
int a[MX],d[MX],tail;
vector<int> v[MX];
LL dp[MX], last[MX], pre[MX], d2[MX];
int ans[MX];
inline void upd(LL &x){
x = (x%mod+mod)%mod;
}
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif // LOCAL
int n;
scanf("%d",&n);
for(int i = 1; i <= n ;i++){
scanf("%d",&a[i]);
}
for(int i = 1; i <= n ;i++){
int l = 1, r = tail;
while(l <= r){
int mid = (l+r)>>1;
if(d[mid] < a[i]) l = mid+1;
else r = mid-1;
}
d[l] = a[i];
if(l > tail) ++tail;
v[l].push_back(i);
}
for(int i = tail; i >= 1; i--){
if(i == tail) {
for(int j = v[i].size()-1; j >= 0; --j){
int id = v[i][j];
dp[id] = 1;
last[id] = dp[id];
if(j < v[i].size()-1) last[id] += last[v[i][j+1]];
// cout<<i<<" "<<id<<endl;
}
}
else{
int k = v[i+1].size(), l = v[i+1].size();
for(int j = v[i].size()-1; j >= 0; --j){
int jid = v[i][j];
for(--k; k >= 0; --k){
int kid = v[i+1][k];
if(kid < jid) break;
}
++k;
for(--l; l >= 0; --l){
int lid = v[i+1][l];
if(a[lid] > a[jid]) break;
}
++l;
if(k < v[i+1].size() && k < l){
dp[jid] = last[v[i+1][k]];
if(l < v[i+1].size()) dp[jid] -= last[v[i+1][l]];
}
else dp[jid] = 0;
// cout<<i<<" "<<jid<<endl;
last[jid] = dp[jid];
if(j < v[i].size()-1) last[jid] += last[v[i][j+1]];
upd(dp[jid]);
upd(last[jid]);
// cout<<i<<" "<<j<<" "<<last[jid]<<endl;
}
}
}
LL tot = 0;
if(n) tot = last[v[1][0]];
LL totinv = qpow(tot,mod-2);
for(int i = 1; i <= tail; i++){
if(i == 1){
for(int j = 0; j < v[i].size(); ++j){
int id = v[i][j];
d2[id] = 1;
pre[id] = d2[id];
if(j > 0) pre[id] += pre[v[i][j-1]];
// cout<<i<<" "<<j<<" "<<v[i][j]<<endl;
}
}
else{
int k = -1, l = -1;
for(int j = 0; j < v[i].size(); ++j){
int jid = v[i][j];
for(++k; k < v[i-1].size(); ++k){
int kid = v[i-1][k];
if(kid > jid) break;
}
--k;
for(++l; l < v[i-1].size(); ++l){
int lid = v[i-1][l];
if(a[lid] < a[jid]) break;
}
--l;
// cout<<i<<" "<<v[i][j]<<endl;
if(k >= 0 && k > l){
d2[jid] = pre[v[i-1][k]];
if(l < v[i-1].size()) d2[jid] -= pre[v[i-1][l]];
}
else d2[jid] = 0;
pre[jid] = d2[jid];
if(j > 0) pre[jid] += pre[v[i][j-1]];
upd(d2[jid]);
upd(pre[jid]);
// cout<<i<<" "<<j<<" "<<" "<<k<<" "<<l<<" "<<pre[jid]<<endl;
}
}
for(int j = 0; j < v[i].size(); ++j){
int jid = v[i][j];
// cout<<i<<" "<<jid<<" "<<dp[jid]<<" "<<d2[jid]<<" "<<tot<<endl;
ans[jid] = 1LL*dp[jid]*d2[jid]%mod*totinv%mod;
}
}
for(int i = 1; i <= n; i++){
printf("%d%c",ans[i], i==n? '\n' : ' ');
}
return 0;
}