牛客寒假第六场 价值序列

价值序列

题意

给出a1,a2,a3......an各项之差的绝对值之和为M,选出串(1<=i1<=i2<=i3<=i4<=.......in<=n)使得ai1,ai2,ai3,ai4.....aik的各项之间之差的绝对值之和M相等,问有几种选法。

思路

首先会发现,无论去掉哪个点,都不会使最终的值增加。

把题目理解为去掉几个点不影响题目的值

1.画出各点高度的连线图,发现只要两个极值点之间的点去掉均不影响,而要留下极值点。

​ 2.考虑特殊情况,在非极值点的位置,若有值相等,这些值都可以去。

​ 3.在极值点的位置,若极值点附近的点和极值点相等,那么需要留下一个极值点。

​ 4.在起点与终点的位置,若有值相等,无论怎样都要留下一个值!把其当作一个极值点考虑

我们把点都归纳为(没有相等的)上升或者下降的,把相同的点的个数赋给第一个出现该点的位置的计数器,这样我们就把情况简化到 1

而那么每个点对题目的贡献就为 pow(2,num[ i ]),若是极值点,该答案-1,因为要留下一种!

思路

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+7;
const int mod=998244353;
bool vis[N];
int a[N];
int b[N];
int num[N];
int qpow(int x,int n)
{
    int base=1;
    while(n)
    {
        if(n&1)
        {
            base=base*x%mod;
        }
        x=x*x%mod;
        n>>=1;
    }
    return base;
}
void solve()
{
    memset(vis,0,sizeof(vis));
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(num,0,sizeof(num));
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        b[++cnt]=a[i];
        num[cnt]=1;
        while(i<n&&a[i]==a[i+1])
        {
            ++i;
            ++num[cnt];
        }
    }
    vis[1]=vis[cnt]=true;
    for(int i=2;i<=cnt-1;i++)
    {
        if(b[i-1]>b[i]&&b[i]<b[i+1])
        {
            vis[i]=true;
        }
        if(b[i-1]<b[i]&&b[i]>b[i+1])
        {
            vis[i]=true;    
        } 
    }
    long long res=1;
    for(int i=1;i<=n;i++)
    {
        if(vis[i])      //非单调
        {
            res=res*(qpow(2,num[i])-1)%mod; 
        }
        else
        {
            res=res*qpow(2,num[i])%mod;
        }
    }
    cout<<res<<endl;
}
signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        solve();
    }
}
posted @ 2022-03-13 10:29  TimMCBen  阅读(45)  评论(0)    收藏  举报