P11079 「FSLOI Round I」山峦(AC代码)

P11079 「FSLOI Round I」山峦

题目背景

English statement. You must submit your code at the Chinese version of the statement.

山峦是造物主弃的酒杯。

题目描述

如果一个长度至少为三的序列 a 满足以下条件,则称其为一个山峰

  • 设其长度为 m。存在一个 x,满足 2≤x≤m−1,并且使得 a1​,a2​,⋯,ax​ 严格单调递增,ax​,ax+1​,⋯,am​ 严格单调递减。

特别地,称 ��ax​ 为这个山峰的高度。

如果一个序列 �b 满足以下任一条件,则称其为一个山峦

  • �b 序列是一个山峰

  • 可以拆成至少两个连续的子序列,使得每个子序列都是山峰,且从左到右山峰的高度严格单调递增。

比如,序列 {2,4,3,1,5,2,1} 是山峦,因为其可以拆分为 {2,4,3},{1,5,2,1} 两个山峰,且山峰高度严格递增。而序列 {2,4,3,5,2,1} 不是山峦,因为其无法拆分成至少两个连续的子序列,使得每个子序列都是山峰。

现在给定一个长度为 n 的序列 a,小 F 想知道,在 a 的所有子序列中,有多少个是山峦。由于答案可能很大,请输出其对 998244353 取余后的结果。

请注意,在本题中,即使子序列的元素相同,只要子序列的元素在 a 中的位置不同,仍算作不同的子序列。

输入格式

共两行。

第一行一个整数 n,表示序列长度。

第二行 n 个整数 a1​,a2​,⋯,an​,表示 a 序列。

输出格式

共一行。

一个整数,表示是山峦的子序列数量对 998244353 取余的结果。

输入输出样例

输入 #1

4
1 2 2 1

输出 #1

2

输入 #2

7
2 4 3 1 5 2 1

输出 #2

35

输入 #3

20
2 3 5 6 8 7 6 5 6 7 8 8 8 8 4 3 5 6 7 4

输出 #3

15085

说明/提示

【样例 1 解释】

由 a1​,a2​,a4​ 构成的子序列是山峦,由 a1​,a3​,a4​ 构成的子序列是山峦。

【数据规模与约定】

本题采用捆绑测试。

对于 100% 的数据,保证:

  • 1≤n≤500
  • 1≤a_i10^6
子任务分值特殊性质
110n≤18
215n≤80
315A
420B
540

特殊性质 A:序列 a 是山峰。

特殊性质 B:序列 a 中的元素互不相同。


【题解】

考虑 DP,设 f_{i,j,k}​ 为在第 i 个点结束的山峦子序列,其中最右边的一座山峰的山顶高度是 j,现在构成的形状形如 k 的,方案数量。其中 k∈[0,5],对应的形状如图所示:

这里解释一下以上 6 种情况。

第 0 种,由山顶向下走了一格,然后往上走一格。

第 1 种,由山顶向下走了一格,然后向上走了两格以上。

第 2 种,由山顶向下走了两格以上,然后向上走了两格以上。

第 3 种,由山顶向下走了一格,

第 4 种,由山顶向下走了两格以上。

第 5 种,平着走了一格。

接下来考虑状态之间如何转移。

因为从山顶往下走一格之后往上走,若再往下走一格,就不能形成两座并列的山峰了,因为这样它们的一个端点会重合,所以第 0 种情况后,只能往上走。

第 5 种情况也一样,山峰右边是严格递减,左边严格递增,出现两个相邻的相等的数,那一定是一个属于左边那座山的右端点,一个属于右边那座山的左端点。

发现第二维的值域达到了 106,考虑离散化,于是降到 5×102。

最后考虑统计答案,为了形成山峦,序列最右边一定是一座山峰的下降部分,因此 ans=\sum_{i=1}^{n}\sum_{j=1}^{p}(f_{i,j,3}+f_{i,j,4}) ,其中 p 表示离散化后的值域。

设值域 p 与 n 同阶,则时间复杂度为 O(n^3)。

【代码】

#include <bits/stdc++.h>
using namespace std;

#define int long long

#define endl '\n'
#define FRR(file) freopen(file,"r",stdin)
#define FRW(file) freopen(file,"w",stdout)
#define _rep(i,a,b) for (int i=(a);i<=(b);++i)
#define _reps(i,a,b,c) for (int i=(a);i<=(b);c)
#define _rrep(i,a,b) for (int i=(a);i>=(b);--i)
#define _rreps(i,a,b,c) for (int i=(a);i>=(b);c)
#define _iter(i,a) for (auto i=a.begin();i!=a.end();++i)
#define _graph(i,u) for (int i=h[u];~i;i=ne[i])
#define rint register int
#define LL long long
typedef pair<int,int> pii;

const int N=505;
const int mod=998244353;

int n;
int arr[N];
int f[N][N][6];
vector<int> nums;
int p;
bool cmp(const int& a,const int& b) {
    return a<b;
}
signed main() {
    scanf("%lld",&n);
    _rep(i,1,n) scanf("%lld",&arr[i]);
    _rep(i,1,n) nums.emplace_back(arr[i]);
    sort(nums.begin(),nums.end(),cmp);
    nums.erase(unique(nums.begin(),nums.end()),nums.end());
    p=nums.size()-1;
    _rep(i,1,n) arr[i]=lower_bound(nums.begin(),nums.end(),arr[i])-nums.begin();
    _rep(i,1,n) {
        f[i][0][0]=1;
        _rep(j,1,i-1) {
            if (arr[j]<arr[i]) {
                _rep(k,0,p) {
                    f[i][k][0]=(f[i][k][0]+f[j][k][3])%mod;
                    f[i][k][1]=(f[i][k][1]+f[j][k][0]+f[j][k][1])%mod;
                    f[i][k][2]=(f[i][k][2]+f[j][k][2]+f[j][k][4]+f[j][k][5])%mod;
                }
            } else if (arr[j]>arr[i]) {
                _rep(k,0,p) {
                    if (k<arr[j]) {
                        f[i][arr[j]][3]=(f[i][arr[j]][3]+f[j][k][1]+f[j][k][2])%mod;
                    }
                    f[i][k][4]=(f[i][k][4]+f[j][k][3]+f[j][k][4])%mod;
                }
            } else {
                _rep(k,0,p) {
                    f[i][k][5]=(f[i][k][5]+f[j][k][3]+f[j][k][4])%mod;
                }
            }
        }
    }
    int ans=0;
    _rep(i,1,n) {
        _rep(j,0,p) {
            ans=(ans+f[i][j][3]+f[i][j][4])%mod;
        }
    }
    printf("%lld",ans);
    return 0;
}

【AC情况】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值