[atAGC053E]More Peaks More Fun

假设已经确定顺序(且不妨假设$a_{i}<b_{i}$),考虑如何判定是否合法——

显然$a_{i}$不能为峰且峰不能相邻,因此峰数的上限是$n-1$

结论:合法当且仅当存在$k\in [0,n]$使得$\forall 1\le i<k,a_{i+1}<b_{i}$且$\forall k+2\le i\le n,a_{i-1}<b_{i}$

为了描述方便,称第$i$组先加入$a_{i}$再加入$b_{i}$为顺序,反之为逆序

充分性:若满足此条件,将$[1,k]$顺序加入且$(k,n]$逆序加入,根据条件不难得到$\forall i\not\in \{k,k+1\},b_{i}$均是峰,同时在$b_{k}$和$b_{k+1}$中较大的一项也总是峰(特别的,当$k\in \{0,n\}$时之前已经有$n-1$个峰)

必要性:对于$i\in [1,n)$,若$i$是顺序且$i+1$是逆序,那么$b_{i}$和$b_{i+1}$中至少有一个不为峰

特别的,若1是逆序或$n$是顺序,那么$b_{1}$或$b_{n}$不为峰(可以理解为0是顺序且$n+1$是逆序)

结合两者,即存在$k\in [0,n]$,满足$[1,k]$为顺序$,(k,n]$为逆序且$\forall i\not\in\{k,k+1\},b_{i}$均是峰,也即条件

进一步的,注意到$k$仅是确定范围,因此总可以取$k=\min_{1\le i\le n,a_{i+1}>b_{i}}i$(约定$a_{n+1}=\infty$),并判定后者是否成立

回到原问题,考虑初始将其按$b_{i}$从小到大排序,并记$U_{i}=\sum_{i<j,a_{j}<b_{i}}1$

对于$k=n$的情况,考虑从后往前依次加入,第$i$个可行的位置有$U_{i}+1$个(注意$b_{i}$的单调性),因此方案数为$\prod_{i=1}^{n}(U_{i}+1)$

对于$k<n$的情况,枚举$k$和$k+1$对应的编号$x$和$y$(保证$a_{y}>b_{x}$,进而显然$x<y$),将$(k,n]$翻转,问题即可以看作构造两个分别以$x$和$y$结尾的序列(条件类似$k=n$),类似地方案数为$\prod_{i=1}^{x-1}U_{i}\prod_{i=x+1}^{y-1}(U_{i}+1)\prod_{i=y+1}^{n}(U_{i}+2)$(考虑结尾能否选)

关于这个问题,用一个树状数组维护即可,时间复杂度为$o(n\log n)$,可以通过

[atAGC053E]More Peaks More Fun
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 #define mod 1000000007
 5 #define ll long long
 6 struct Data{
 7     int a,b;
 8     bool operator < (const Data &k)const{
 9         return b<k.b;
10     }
11 }a[N];
12 int n,ans,inv[N],U[N],pre[N],suf1[N],suf2[N],f[N<<1];
13 int lowbit(int k){
14     return (k&(-k));
15 }
16 void update(int k,int x){
17     while (k<=(n<<1)){
18         f[k]=(f[k]+x)%mod;
19         k+=lowbit(k);
20     }
21 }
22 int query(int k){
23     int ans=0;
24     while (k){
25         ans=(ans+f[k])%mod;
26         k-=lowbit(k);
27     }
28     return ans;
29 }
30 int main(){
31     inv[0]=inv[1]=1;
32     for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
33     scanf("%d",&n);
34     for(int i=1;i<=n;i++){
35         scanf("%d%d",&a[i].a,&a[i].b);
36         if (a[i].a>a[i].b)swap(a[i].a,a[i].b);
37     }
38     sort(a+1,a+n+1);
39     for(int i=n;i;i--){
40         U[i]=query(a[i].b);
41         update(a[i].a,1);
42     }
43     pre[0]=suf1[n+1]=suf2[n+1]=1;
44     for(int i=1;i<=n;i++)pre[i]=(ll)pre[i-1]*U[i]%mod;
45     for(int i=n;i;i--)suf1[i]=(ll)suf1[i+1]*(U[i]+1)%mod;
46     for(int i=n;i;i--)suf2[i]=(ll)suf2[i+1]*(U[i]+2)%mod*inv[U[i]+1]%mod;
47     memset(f,0,sizeof(f));
48     ans=suf1[1];
49     for(int i=n;i;i--){
50         ans=(ans+(ll)pre[i-1]*suf1[i+1]%mod*(query(n<<1)-query(a[i].b)+mod))%mod;
51         update(a[i].a,(ll)suf2[i+1]*inv[U[i]+1]%mod);
52     }
53     printf("%d\n",ans);
54     return 0;
55 }
View Code

 

上一篇:C++异步多线程:future、promise、package_task、asyce练习


下一篇:安卓开发:网络图片下载和显示