牛客寒假第六场 价值序列
价值序列
题意
给出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();
}
}