牛客寒假第六場 價值序列
阿新 • • 發佈:2022-03-13
價值序列
題意
給出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(); } }