【JZOJ5605】【NOI2018模擬3.26】Arg
阿新 • • 發佈:2018-05-28
In 過程 sca 如何 LG lis noi pre 第一個
題目描述
給出一個長度為 m 的序列 A, 請你求出有多少種 1...n 的排列, 滿足 A 是它的一個 LIS.
解題思路
如何求出一個序列的LIS?
對於二分的方法,每次插入一個數,將它放到第一個比它大的數的位置處代替之,最後的長度就是LIS的長度。
考慮模擬這個過程,設f[s],表示當前這n個數的是否加入的狀態為s,s是一個三進制數,0表示還沒加入,1表示加入了且仍在當前的LIS中,2表示加入了且被別的數代替了。
同時有限制條件,a[i-1]一定要在a[i]前加入。
#include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <bitset> #include <set> const int maxlongint=2147483647; const int mo=1e9+7; const int N=17; using namespace std; int a[N],n,m,mi[N],vv,v[N],bz[N]; long long f[N*1000000],ans; int main() { scanf("%d%d",&n,&m); mi[0]=1; for(int i=1;i<=n;i++) mi[i]=mi[i-1]*3; for(int i=1;i<=m;i++) scanf("%d",&a[i]),bz[a[i]]=i; f[0]=1; v[0]=1; for(int s=0;s<mi[n]-1;s++) if(f[s]) { int x=s,sum=0,all=1; for(int i=n;i>=1;i--) { int t=x/mi[i-1]; x%=mi[i-1]; sum+=(v[i]=t)==1; all*=v[i]; } if(sum>m) continue; int k=0; for(int i=n;i>=1;i--) { if(!v[i]) { if(bz[i] && !v[a[bz[i]-1]]) continue; if(!k) f[s+mi[i-1]]+=f[s]; else f[s+mi[i-1]+mi[k-1]]+=f[s]; } if(v[i]==1) k=i; } if(all && sum==m) ans+=f[s]; } printf("%lld\n",ans); }
【JZOJ5605】【NOI2018模擬3.26】Arg