ARC115E-LEQ and NEQ【容斥,dp,线段树】
正題
題目鏈接:https://atcoder.jp/contests/arc115/tasks/arc115_d
題目大意
nnn個數字的序列xxx,第xi∈[1,Ai]∩Zx_i\in [1,A_i]\cap Zxi?∈[1,Ai?]∩Z。要求相鄰的不同,求方案數。
1≤n≤5×105,1≤Ai≤1091\leq n\leq 5\times 10^5,1\leq A_i\leq 10^91≤n≤5×105,1≤Ai?≤109
解題思路
考慮容斥,如果有kkk個相鄰的相等那么容斥系數就是(?1)k(-1)^k(?1)k。那我們把nnn分為若干個連續的相同段,然后每一段的容斥系數分開算就好了,這樣就是一個可以dpdpdp的式子了。
設fif_ifi?表示以iii結尾的段時的值,那么有轉移方程
fi=∑j=0i?1fj×min{Ak}(k∈(j,i])×(?1)i?j?1f_i=\sum_{j=0}^{i-1}f_j\times min\{A_k\}(k\in(j,i])\times (-1)^{i-j-1}fi?=j=0∑i?1?fj?×min{Ak?}(k∈(j,i])×(?1)i?j?1
這個min{Ak}min\{A_k\}min{Ak?}每次加入一個新的時候會影響一個后綴,用單調棧找到這個后綴,然后把fif_ifi?丟進線段樹里。
而那個容斥系數就是每次整個線段樹乘上一個(?1)(-1)(?1),這個丟到外面處理就好了。
時間復雜度O(nlog?n)O(n\log n)O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=5e5+10,M=N<<2,P=998244353; ll n,a[N],q[N],f[N]; ll w[M],lazy[M],v[M]; void Downdata(ll x){if(!lazy[x])return;w[x*2]=v[x*2]*lazy[x]%P;w[x*2+1]=v[x*2+1]*lazy[x]%P;lazy[x*2]=lazy[x*2+1]=lazy[x];return; } void Change(ll x,ll L,ll R,ll l,ll r,ll c){if(L==l&&R==r){lazy[x]=c;w[x]=v[x]*c%P;return;}ll mid=(L+R)>>1;Downdata(x);if(r<=mid)Change(x*2,L,mid,l,r,c);else if(l>mid)Change(x*2+1,mid+1,R,l,r,c);else Change(x*2,L,mid,l,mid,c),Change(x*2+1,mid+1,R,mid+1,r,c);w[x]=(w[x*2]+w[x*2+1])%P;v[x]=(v[x*2]+v[x*2+1])%P;return; } void Insert(ll x,ll L,ll R,ll pos,ll c){if(L==R){v[x]=c;w[x]=c*lazy[x]%P;return;}ll mid=(L+R)>>1;Downdata(x);if(pos<=mid)Insert(x*2,L,mid,pos,c);else Insert(x*2+1,mid+1,R,pos,c);w[x]=(w[x*2]+w[x*2+1])%P;v[x]=(v[x*2]+v[x*2+1])%P;return; } signed main() {scanf("%lld",&n);ll top=1;Insert(1,1,n,1,P-1);for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);while(top>0&&a[i]<a[q[top]])top--;Change(1,1,n,q[top]+1,i,a[i]);q[++top]=i;f[i]=(i&1)?(P-w[1]):w[1];if(i!=n)Insert(1,1,n,i+1,P-w[1]);}printf("%lld\n",f[n]);return 0; }總結
以上是生活随笔為你收集整理的ARC115E-LEQ and NEQ【容斥,dp,线段树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我用过最棒的一款投屏软件不错的投屏软件
- 下一篇: 笔记本如何选购如何选购笔记本电脑技巧全攻