题解 排列

传送门

正解是24分治

写的时候想对位置分段,但只会处理1234和4321

但其实可以同时对位置和值域分段
我们枚举两个数,尝试用这两个数将位置和值域都分成两段
发现除 \((1, 2)\ (1, 4)\ (3, 4)\) 外都满足这个性质
分段后就变成了在区间 \(l, r\) 内选一个值域在 \(a, b\) 内的数的方案数,可以二维前缀和实现

但刚才那种方法处理不了 \(2413\)\(3142\)
对于 \(2143\),可以枚举3和4的位置,则问题转化为在两个区间内各选一个数,前面的数比后面的大的方案数
可以树状数组+广义扫描线实现
\(3142\) 把b数组reverse一下就是 \(2413\)

看起来非常令人愉悦的 Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

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

namespace task1{
	ll ans;
	struct sub1{
		int bin[N], bin2[N];
		void upd(int i, int dat) {for (; i<=n; i+=i&-i) bin[i]+=dat;}
		int qcnt(int i) {int ans=0; for (; i; i-=i&-i) ans+=bin[i]; return ans;}
		void upd2(int i, int dat) {for (; i<=n; i+=i&-i) bin2[i]+=dat;}
		int qans(int i) {int ans=0; for (; i; i-=i&-i) ans+=bin2[i]; return ans;}
		void clear() {
			memset(bin, 0, sizeof(bin));
			memset(bin2, 0, sizeof(bin2));
		}
		void add(int dat) {
			int tem=qcnt(dat);
			upd(dat, 1);
			upd2(dat, tem);
		}
		int query(int val) {return qans(val);}
	}t1;
	struct sub2{
		int bin[N], bin2[N];
		void upd(int i, int dat) {for (; i; i-=i&-i) bin[i]+=dat;}
		int qcnt(int i) {int ans=0; for (; i<=n; i+=i&-i) ans+=bin[i]; return ans;}
		void upd2(int i, int dat) {for (; i; i-=i&-i) bin2[i]+=dat;}
		int qans(int i) {int ans=0; for (; i<=n; i+=i&-i) ans+=bin2[i]; return ans;}
		void clear() {
			memset(bin, 0, sizeof(bin));
			memset(bin2, 0, sizeof(bin2));
		}
		void add(int dat) {
			int tem=qcnt(dat);
			upd(dat, 1);
			upd2(dat, tem);
		}
		int query(int val) {return qans(val);}
	}t2;
	void solve() {
		for (int i=2; i<=2; ++i) {
			t1.clear(); t2.clear();
			for (int j=1; j<=i; ++j) t1.add(b[j]);
			for (int j=n; j>i; --j) t2.add(b[j]);
			for (int j=1; j<=n; ++j) {
				cout<<"j: "<<j<<' '<<t1.query(j)<<' '<<t2.query(j)<<endl;
				ans+=t1.query(j)*t2.query(j);
			}
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task2{
	ll dp[N][5], ans;
	void solve() {
		for (int i=1; i<=n; ++i) dp[i][1]=1;
		for (int i=1; i<=n; ++i) {
			for (int k=1; k<i; ++k) if (b[k]<b[i]) {
				for (int j=2; j<=4; ++j) {
					dp[i][j]+=dp[k][j-1];
				}
			}
		}
		for (int i=1; i<=n; ++i) ans+=dp[i][4];
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task3{
	ll ans;
	void dfs(int u, vector<int> v) {
		if (v.size()==4) {++ans; return ;}
		for (int i=u; i<=n; ++i) {
			v.push_back(b[i]);
			int t=v.size();
			for (int j=1; j<=t; ++j) {
				for (int k=j+1; k<=t; ++k) {
					if ((a[j]-a[k])*(v[j-1]-v[k-1])<=0) goto jump;
				}
			}
			dfs(i+1, v);
			jump: ;
			v.pop_back();
		}
	}
	void solve() {
		dfs(1, vector<int>());
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task{
	int sum[N][N], bin1[N], bin2[N];
	inline int query(int l1, int r1, int l2, int r2) {return sum[r1][r2]-sum[l1-1][r2]-sum[r1][l2-1]+sum[l1-1][l2-1];}
	inline void upd1(int i, int dat) {for (; i; i-=i&-i) bin1[i]+=dat;}
	inline int query1(int i) {int ans=0; for (; i<=n; i+=i&-i) ans+=bin1[i]; return ans;}
	inline void upd2(int i, int dat) {for (; i<=n; i+=i&-i) bin2[i]+=dat;}
	inline int query2(int i) {int ans=0; for (; i; i-=i&-i) ans+=bin2[i]; return ans;}
	void solve() {
		int it=0;
		for (int i=1; i<=4; ++i) it=it*10+a[i];
		for (int i=1; i<=n; ++i) sum[i][b[i]]=1;
		for (int i=1; i<=n; ++i) 
			for (int j=1; j<=n; ++j)
				sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
		ll ans=0, now;
		switch (it) {
			case 1234: for (int i=2; i<n; ++i) for (int j=i+2; j<=n; ++j) if (b[i]<b[j]-1) ans+=query(1, i-1, 1, b[i]-1)*query(i+1, j-1, b[i]+1, b[j]-1); break;
			case 1243: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]<b[j]-1) ans+=query(1, i-1, 1, b[i]-1)*query(j+1, n, b[i]+1, b[j]-1); break;
			case 1324: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]) ans+=query(1, i-1, 1, b[j]-1)*query(j+1, n, b[i]+1, n); break;
			case 1342: for (int i=2; i<n; ++i) for (int j=i+2; j<=n; ++j) if (b[i]>b[j]) ans+=query(1, i-1, 1, b[j]-1)*query(i+1, j-1, b[i]+1, n); break;
			case 1423: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]+1) ans+=query(1, i-1, 1, b[j]-1)*query(j+1, n, b[j]+1, b[i]-1); break;
			case 1432: for (int i=2; i<n; ++i) for (int j=i+2; j<=n; ++j) if (b[i]>b[j]+1) ans+=query(1, i-1, 1, b[j]-1)*query(i+1, j-1, b[j]+1, b[i]-1); break;
			case 2134: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]<b[j]) ans+=query(i+1, j-1, 1, b[i]-1)*query(j+1, n, b[j]+1, n); break;
			case 2143: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]<b[j]-1) ans+=query(i+1, j-1, 1, b[i]-1)*query(j+1, n, b[i]+1, b[j]-1); break;
			case 2314: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]+1) ans+=query(1, i-1, b[j]+1, b[i]-1)*query(j+1, n, b[i]+1, n); break;
			case 2341: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[j]>b[i]+1) ans+=query(i+1, j-1, b[i]+1, b[j]-1)*query(j+1, n, 1, b[i]-1); break;
			case 2431: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]<b[j]) ans+=query(i+1, j-1, b[j]+1, n)*query(j+1, n, 1, b[i]-1); break;
			case 3124: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]>b[j]) ans+=query(i+1, j-1, 1, b[j]-1)*query(j+1, n, b[i]+1, n); break;
			case 3214: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]>b[j]+1) ans+=query(i+1, j-1, b[j]+1, b[i]-1)*query(j+1, n, b[i]+1, n); break;
			case 3241: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]<b[j]) ans+=query(1, i-1, b[i]+1, b[j]-1)*query(j+1, n, 1, b[i]-1); break;
			case 3412: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]>b[j]+1) ans+=query(i+1, j-1, b[i]+1, n)*query(j+1, n, b[j]+1, b[i]-1); break;
			case 3421: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]) ans+=query(1, i-1, b[j]+1, b[i]-1)*query(j+1, n, 1, b[j]-1); break;
			case 4123: for (int i=1; i<n; ++i) for (int j=i+2; j<n; ++j) if (b[i]>b[j]+1) ans+=query(i+1, j-1, 1, b[j]-1)*query(j+1, n, b[j]+1, b[i]-1); break;
			case 4132: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]<b[j]-1) ans+=query(1, i-1, b[j]+1, n)*query(j+1, n, b[i]+1, b[j]-1); break;
			case 4213: for (int i=2; i<n; ++i) for (int j=i+2; j<=n; ++j) if (b[i]<b[j]) ans+=query(1, i-1, b[j]+1, n)*query(i+1, j-1, 1, b[i]-1); break;
			case 4231: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]<b[j]) ans+=query(1, i-1, b[j]+1, n)*query(j+1, n, 1, b[i]-1); break;
			case 4312: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]+1) ans+=query(1, i-1, b[i]+1, n)*query(j+1, n, b[j]+1, b[i]-1); break;
			case 4321: for (int i=2; i<n; ++i) for (int j=i+1; j<n; ++j) if (b[i]>b[j]) ans+=query(1, i-1, b[i]+1, n)*query(j+1, n, 1, b[j]-1); break;
			case 3142: reverse(b+1, b+n+1); case 2413:
			for (int i=4; i<=n; ++i) {
				now=0;
				memset(bin1, 0, sizeof(bin1));
				memset(bin2, 0, sizeof(bin2));
				for (int j=2; j<i; ++j) if (b[j]<b[i]) upd2(b[j], 1);
				for (int j=2; j<i-1; ++j) {
					if (b[j]<b[i]) {now-=query1(b[j]); upd2(b[j], -1);}
					if (b[j-1]<b[i]) {now+=query2(b[j-1]); upd1(b[j-1], 1);}
					if (b[j]>b[i]) ans+=now;
				}
			}
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

signed main()
{
	freopen("c.in", "r", stdin);
	freopen("c.out", "w", stdout);

	n=read();
	for (int i=1; i<=4; ++i) a[i]=read();
	for (int j=1; j<=n; ++j) b[j]=read();
	#if 0
	if (a[1]==1 && a[2]==2 && a[3]==3 && a[4]==4) task2::solve();
	else if (a[1]==4 && a[2]==3 && a[3]==2 && a[4]==1) {
		for (int j=1; j<=n; ++j) b[j]=-b[j];
		task2::solve();
	}
	task3::solve();
	#endif
	task::solve();
	
	return 0;
}
posted @ 2021-09-29 20:21  Administrator-09  阅读(2)  评论(0编辑  收藏  举报