P7444-「EZEC-7」猜排列【dp】
正題
題目鏈接:https://www.luogu.com.cn/problem/P7444
題目大意
一個長度為nnn的排列,已知每個cic_ici?表示那個排列中mexmexmex為iii的區間個數。求滿足條件的排列個數
1≤n≤5×105,ci≥0,∑i=1nci=n(n+1)2?11\leq n\leq 5\times 10^5,c_i\geq 0,\sum_{i=1}^nc_i=\frac{n(n+1)}{2}-11≤n≤5×105,ci?≥0,∑i=1n?ci?=2n(n+1)??1
解題思路
考慮一個樸素的dpdpdp,設fi,l,rf_{i,l,r}fi,l,r?表示加入了1~i1\sim i1~i,然后最大區間是[l,r][l,r][l,r]時的方案。
那么每次插入一個數iii的時候如果ci=0c_i=0ci?=0那么它一定在目前的最大區間里,否則需要擴展到區間外,每次有往左或者往右擴展。
不難發現對于1~i1\sim i1~i擴展到lll,那么rrr是固定的,所以我們可以直接用fi,lf_{i,l}fi,l?來表示狀態,但是這樣還是O(n2)O(n^2)O(n2)的,其實狀態數比較少的,因為對于一個iii來說需要擴展的aia_iai?都是一些倍數形的。
其實總狀態數不會超過∑i=1nai\sum_{i=1}^n\sqrt{a_i}∑i=1n?ai??,因為上限很難到,所以用個vectorvectorvector記錄一下狀態就能夠過了
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define ll long long using namespace std; const ll N=5e5+10,P=998244353; ll n,a[N],f[2][N],ed[2][N],vis[N]; vector<int> v[2]; signed main() {scanf("%lld",&n);for(ll i=0;i<n;i++)scanf("%lld",&a[i]);ll Ans=0,s=0;for(ll i=1;i<=n;i++){ll l=i-1,r=n-i;if(l*(l+1)+r*(r+1)==a[0]*2)s=i,Ans++;}if(!Ans)return puts("0")&0;f[0][s]=1;ed[0][s]=s;v[0].push_back(s);for(ll i=1;i<n-1;i++){v[i&1].clear();for(ll p=0;p<v[~i&1].size();p++){ll l=v[~i&1][p],r=ed[~i&1][l];if(vis[l]==i)continue;vis[l]=i;if(!a[i]){if(r-l-i<0)continue;(f[i&1][l]+=f[~i&1][l]*(r-l-i+1)%P)%=P;ed[i&1][l]=r;v[i&1].push_back(l);}else{ll lk=l,rk=n-r+1;if(a[i]%lk==0){ll nr=r+a[i]/lk;(f[i&1][l]+=f[~i&1][l])%=P;ed[i&1][l]=nr;v[i&1].push_back(l);} if(a[i]%rk==0){ll nl=l-a[i]/rk;(f[i&1][nl]+=f[~i&1][l])%=P;ed[i&1][nl]=r;v[i&1].push_back(nl);}}}for(ll p=0;p<v[~i&1].size();p++)f[~i&1][v[~i&1][p]]=0;}ll ans=0;for(ll i=1;i<=n;i++)(ans+=f[(n-2)&1][i])%=P;printf("%lld\n",ans*Ans%P);return 0; }總結
以上是生活随笔為你收集整理的P7444-「EZEC-7」猜排列【dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OPPO 将发布全新影像战略,一加 12
- 下一篇: P5137-polynomial【倍增】