「BZOJ 4361」isn 题解

「BZOJ 4361」isn 题解


知识点

DP,组合数学,容斥,树状数组。

分析

首先,我们不考虑「非降时停止」这个限制,那么则可用 DP 求解。

\(f_{i,j}\) 表示 \(1\sim i\) 中,组成一个长度为 \(j\) 的非降子序列的方案数。初态和转移式:

\[\forall i,f_{i,1} = 1\\ f_{i,j} = \sum_{k<i} f_{k,j-1}[a_{k} \le a_i] \\ \]

这个问题答案就是:

\[\sum_{j=1}^n j\cdot (n-j)!\sum_{i=j}^{n} f_{i,j} \]

然后我们来考虑「非降时停止」:其实只要把每个不合法的从原本的减掉即可,而这些不合法的我们都可以从已有的 DP 状态中推出来。

我们简化一下,设 \(g_i\) 表示所有组成长度为 \(i\) 的非降子序列的方案数,即:

\[g_i = \sum_{j=i}^n f_{j,i} \\ \]

那么考虑「非降时停止」的组成长度为 \(i\) 的非降子序列方案数就是:\((n-i)!\cdot g_i - (i+1)(n-i-1)!\cdot g_{i+1}\)。所以累加即可。

DP 暴力可做到 \(O(n^3)\),离散化后用树状数组即可优化到 \(O(n^2\log_2{n})\)

代码

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define FOR(i,a,b) for(int i(a);i<=(int)(b);++i)
#define DOR(i,a,b) for(int i(a);i>=(int)(b);--i)
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define EDGE(g,i,x,y) for(int i=(g).h[(x)],y=(g)[(i)].v;~i;y=(g)[(i=(g)[i].nxt)>0?i:0].v)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);return Main();}signed Main
using namespace std;
constexpr int N(2e3+10);

namespace Modular {
#define Mod 1000000007
	int fac[N];
    //Modular
	void Init(const int n=N-5) {
		FOR(i,fac[0]=1,n)fac[i]=mul(fac[i-1],i);
	}
} using namespace Modular;

int n,ans;
int a[N],b[N],f[N];

class BIT {
private:
	int c[N];
public:
	void Init() { RCL(c+1,0,int,b[0]); }
#define lowbit(i) ((i)&-(i))
	void Plus(int x,int d) { if(x>0)for(; x<=b[0]; x+=lowbit(x))toadd(c[x],d); }
#undef lowbit
	int Sum(int x) {
		int ans(0);
		if(x>0)for(; x; x&=x-1)toadd(ans,c[x]);
		return ans;
	}
} bit;

signed main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	cin>>n,Init(n),ans=mul(n,fac[n-1]);
	FOR(i,1,n)cin>>a[i],b[i]=a[i],f[i]=1;
	sort(b+1,b+n+1),b[0]=unique(b+1,b+n+1)-b-1;
	FOR(i,1,n)a[i]=lower_bound(b+1,b+b[0]+1,a[i])-b;
	FOR(len,2,n) {
		bit.Init(),bit.Plus(a[len-1],f[len-1]),f[len-1]=0;
		int sum(0);
		FOR(i,len,n) {
			int tmp(bit.Sum(a[i]));
			bit.Plus(a[i],f[i]),toadd(sum,f[i]=tmp);
		}
		toadd(ans,Mod-mul(sum,len-1,fac[n-len]));
	}
	cout<<ans<<endl;
	return 0;
}

posted @ 2025-06-11 20:25  Add_Catalyst  阅读(6)  评论(0)    收藏  举报