zoukankan      html  css  js  c++  java
  • [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)$,可以通过

     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
  • 相关阅读:
    第二次冲刺个人工作总结06
    第二次冲刺个人工作总结05
    第十三周学习进度
    第二次冲刺工作总结04
    软件工程课堂作业——寻找水王2
    第二次冲刺个人工作总结03
    第二次冲刺周期个人工作总结02
    第二次冲刺个人工作总结01
    第二次冲刺会议
    git 的更新代码的取消
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15727728.html
Copyright © 2011-2022 走看看