上海月赛5月月赛乙组T1题解
题目:
题目描述
Alice 有一个长度为 \(n\) 的排列 \(p\),请帮她求出 \(p\) 有多少个非空子序列满足逆序对数与 \(p\) 本身的逆序对数相等。
由于答案可能很大,你只需要输出答案对 \(998244353\) 取模后的值。
一个长度为 \(n\) 的排列是一个包含 \(1 \sim n\) 各一次的数组。
数组 \(a_{1 \ldots n}\) 的逆序对数是满足 \(1 \leq i < j \leq n\) 且 \(a_i > a_j\) 的 \((i, j)\) 对数。
数组 \(a\) 的子序列是从其中删除若干元素,将剩余元素按顺序拼接起来所得到的序列。
输入格式
第一行一个整数 \(T\) 表示数据组数,对于每组数据:
第一行一个整数 \(n\)。
第二行 \(n\) 个整数 \(p_1, p_2, \ldots, p_n\)。
输出格式
对于每组数据,输出一行一个整数表示答案。
数据范围
- 对于 \(30\%\) 的数据,\(\sum n \leq 20\)。
- 对于 \(60\%\) 的数据,\(\sum n \leq 5000\)。
- 对于 \(100\%\) 的数据,\(1 \leq T \leq 1000\),\(2 \leq n \leq 10^5\),\(\sum n \leq 5 \times 10^5\)。
样例数据
输入:
2
5
1 2 3 4 5
6
3 1 2 4 6 5
输出:
31
2
说明
- 对于第一组数据,任何非空子序列的逆序对数都是 \(0\),与 \(p\) 的逆序对数相等,答案为 \(2^5 - 1 = 31\)。
- 对于第二组数据,\(p\) 的逆序对数是 \(3\),子序列 \([3, 1, 2, 4, 6, 5]\) 和 \([3, 1, 2, 6, 5]\) 的逆序对数与其相等。
解法:
首先发现这个子序列必须包含所有逆序对才合法,不用担心顺序,因为子序列不会影响顺序,所以问题就变成了求包含所有逆序对的子序列的个数,明显就变得很简单了,因为逆序对是注定要选的,其他位置不用选。
注意空子序列的情况不能算进去。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define mod 998244353
const int N = 5e5+5;
int a[N],b[N];
int d[N];
void dfs(int l,int r)
{
if(l == r)
{
return;
}
int mid = l+r>>1;
dfs(l,mid);
dfs(mid+1,r);
int L = l,R = mid+1,k = l-1;
while(L<=mid&&R<=r)
{
if(a[L]<=a[R])
{
b[++k] = a[L++];
}
else
{
d[L]++;
d[mid+1]--;
d[R]++;
d[R+1]--;
b[++k] = a[R++];
}
}
while(L<=mid)
{
b[++k] = a[L++];
}
while(R<=r)
{
b[++k] = a[R++];
}
for(int i = l;i<=r;i++)
{
a[i] = b[i];
}
}
signed main()
{
int t;
scanf("%lld",&t);
while(t--)
{
memset(d,0,sizeof(d));
int n;
scanf("%lld",&n);
for(int i = 1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
dfs(1,n);
int num = 0,y = 0,q = 0;
for(int i = 1;i<=n;i++)
{
num+=d[i];
if(!num)
{
y++;
}
}
q = y;
int ans = 1,x = 2;
while(y)
{
if(y&1)
{
ans = ans*x%mod;
}
x = x*x%mod;
y>>=1;
}
printf("%lld\n",ans-(q == n));
}
return 0;
}

浙公网安备 33010602011771号