上海月赛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;
}
posted @ 2025-05-26 18:54  林晋堃  阅读(45)  评论(0)    收藏  举报