AGC053E-More Peaks More Fun【计数】

正题

题目链接:https://atcoder.jp/contests/agc053/tasks/agc053_e


题目大意

给出\(n\)个二元组\((a_i,b_i)\),求有多少个\(1\sim n\)的排列\(p\)满足:

  1. 你可以将一些\((a_i,b_i)\)变为\((b_i,a_i)\)
  2. 定义序列\(x_{2i-1}=a_{p_i},x_{2i}=b_{p_i}\),使得\(x\)恰好有\(n-1\)个峰值。

保证\(a_i,b_i\)互不相同。

\(10^9+7\)取模

\(1\leq n\leq 2\times 10^5,1\leq a_i,b_i\leq 2n\)


解题思路

考虑怎样的排列满足条件,因为每个二元组的位置最多产生一个峰值,所以我们可以考虑没有产生峰值的位置。
先令所有的\(a_i<b_i\),那么如果是最后一个二元组没有产生峰值,那么我们应该会排列成\(a\dot{b}a\dot{b}a\dot{b}a\dot{b}a\dot{b}...ab\)的形式,那么就要求了\(b_i>a_{i+1}\)
如果是中间的某个位置\(p\)没有产生峰值,那么应该是\(a\dot{b}a\dot{b}...ab\dot{b}a\dot{b}a\dot{b}a\dot{b}a...\dot{b}a\)的形式。
那么就要求\(b_i>a_{i+1}(i<p),b_i\geq a_{i+1}(i>p+1),b_{p+1}>b_{p}\),有可能我们将\(p+1\sim n\)都翻转一下也是合法的,所以为了防止计算重复,我们强制要求\(a_{p+1}>b_p\)就可以了。

那么考虑如何计数,我们记\(f_i\)表示满足\(b_j>b_i,a_j<a_i\)的二元组个数,然后我们从\(b\)小的到\(b\)大的填。

那么对于第一种情况,我们答案就是\(\prod_{i=1}^n (f_i+1)\)。至于第二种情况,我们枚举考虑\(p_i\)\(p_{i+1}\)分别是\(x,y\)那么答案就是

\[\prod_{i=1}^{x-1}f_i\times \prod_{i=x+1}^{y-1}(f_{i}+1)\times \prod_{i=y+1}(f_{i}+2) \]

用个树状数组计数就好了,时间复杂度:\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=4e5+10,P=1e9+7;
struct node{
	ll a,b;
}a[N];
ll n,w[N],t[N],f[N][3];
void Change(ll x,ll val){
	while(x<=2*n){
		(t[x]+=val)%=P;
		x+=lowbit(x);
	}
	return;
}
ll Ask(ll x){
	ll ans=0;
	while(x){
		(ans+=t[x])%=P;
		x-=lowbit(x);
	}
	return ans;
}
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
ll inv(ll x)
{return power(x,P-2);}
bool cmp(node x,node y)
{return x.b<y.b;}
signed main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld%lld",&a[i].a,&a[i].b);
		if(a[i].a>a[i].b)swap(a[i].a,a[i].b);
	}
	sort(a+1,a+1+n,cmp);
	ll ans=1;
	for(ll i=n;i>=1;i--){
		w[i]=Ask(a[i].b);
		ans=ans*(w[i]+1)%P;
		Change(a[i].a,1);
	}
	f[0][0]=f[0][1]=f[0][2]=1;
	for(ll i=1;i<=n;i++)
		for(ll j=0;j<3;j++)
			f[i][j]=f[i-1][j]*(w[i]+j)%P;
	memset(t,0,sizeof(t));
	for(ll i=1;i<=n;i++){
		(ans+=Ask(a[i].a)*f[n][2]%P*inv(f[i][2])%P*f[i-1][1]%P)%=P;
		Change(a[i].b,f[i-1][0]*inv(f[i][1])%P);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-05-20 16:19  QuantAsk  阅读(25)  评论(0编辑  收藏  举报