• [atAGC054E]ZigZag Break


    结论:(不妨假设$p_{1}<p_{n}$)${p_{i}}$合法当且仅当$exists 1le ile n-1$,使得$p_{1}ge p_{i}$且$p_{i+1}ge p_{n}$

    充分性——

    为了方便,在删除一个元素后,$i$和$n$也随之变化(指向原来的元素,若删除$p_{i}$或$p_{n}$会补充说明)

    对${p_{1},p_{2},...,p_{i}}$这个子问题不断删除(直至不能删除),显然最终必然是$p_{1}<p_{2}<...<p_{i}$(否则一定仍可以操作),同理可得后者也为$p_{i+1}>p_{i+2}>...>p_{n}$

    如果$ige 3$或$ile n-3$,不妨再删除$p_{i}$(并将$i$减小1)或删除$p_{i+1}$,重复此过程后即有$n-2le ile 2$,进而对$i$和$n$分类讨论,最终序列一定形如${2,1},{2,3,1},{1,3,2}$或${2,1,4,3}$,也即合法

    必要性——

    对$n$从小到大归纳,$n=2$时显然成立(取$i=1$即可)

    考虑$n=k+1$时,反证若存在排列${p_{i}}$合法但不存在$i$满足上述条件,假设其第一次删除的是$p_{i}$,由归纳假设删除后要存在$i$(满足上述条件),显然必然是$p_{1}le p_{i-1}$且$p_{i+1}ge p_{n}$

    进而对$p_{i}$的值分类讨论,不难发现删除前也存在$i$,与假设矛盾,即得证

    (类似地,在$p_{1}>p_{n}$时即要求$exists 1le ile n-1$,使得$p_{1}le p_{i}$且$p_{i+1}le p_{n}$)

    由于已经确定$p_{1}$,考虑枚举$p_{n}$(不妨仍假设$p_{1}<p_{n}$),并统计不合法的方案数——

    将数分为三类,即$[1,p_{1}],(p_{1},p_{n}),[p_{n},n]$,那么即要求第三类数不接在第一类数的后面

    初始序列中即有一个第一类数和第三类数(由于$nge 3$,这两个数一定不会相邻),并依次插入第2类、第1类和第3类数(注意顺序,并且要考虑初始的数),显然方案即
    $$
    (p_{n}-p_{1}-1)!frac{(p_{n}-3)!}{(p_{n}-p_{1}-2)!}frac{(n-p_{1}-2)!}{(p_{n}-p_{1}-2)!}=(p_{n}-p_{1}-1)frac{(p_{n}-3)!(n-p_{1}-2)!}{(p_{n}-p_{1}-2)!}
    $$

    该式可以$o(1)$计算,但由于要枚举$p_{n}$,时间复杂度为$o(tn)$,无法通过

    进一步的,枚举$k=p_{n}-p_{1}-2$​,原式即
    $$
    (n-p_{1}-2)!sum_{k=0}^{n-p_{1}-2}frac{(k+1)(k+p_{1}-1)!}{k!}\=(n-p_{1}-2)!left(sum_{k=0}^{n-p_{1}-2}frac{(k+p_{1}-1)!}{k!}+sum_{k=0}^{n-p_{1}-2}frac{(k+p_{1}-1)!}{(k-1)!} ight)\=(n-p_{1}-2)!left((p_{1}-1)!sum_{k=0}^{n-p_{1}-2}{k+p_{1}-1choose p_{1}-1}+p_{1}!sum_{k=0}^{n-p_{1}-2}{k+p_{1}-1choose p_{1}} ight)\=(n-p_{1}-2)!left((p_{1}-1)!{n-2choose p_{1}}+p_{1}!{n-2choose p_{1}+1} ight)
    $$
    类似地,可以得到$p_{n}<p_{1}$​的情况,答案为
    $$
    (p_{1}-3)!left((n-p_{1})!{n-2choose n-p_{1}+1}+(n-p_{1}+1)!{n-2choose n-p_{1}+2} ight)
    $$
    时间复杂度为$o(t)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1000005
     4 #define mod 998244353
     5 #define ll long long
     6 int t,n,x,ans,fac[N],inv[N];
     7 int C(int n,int m){
     8     return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
     9 }
    10 int main(){
    11     fac[0]=inv[0]=inv[1]=1; 
    12     for(int i=1;i<N;i++)fac[i]=(ll)fac[i-1]*i%mod;
    13     for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    14     for(int i=1;i<N;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
    15     scanf("%d",&t);
    16     while (t--){
    17         scanf("%d%d",&n,&x);
    18         ans=fac[n-1];
    19         if (x+2<=n){
    20             int s=((ll)fac[x-1]*C(n-2,x)+(ll)fac[x]*C(n-2,x+1))%mod;
    21             ans=(ans-(ll)fac[n-x-2]*s%mod+mod)%mod;
    22         }
    23         if (x>=3){
    24             int s=((ll)fac[n-x]*C(n-2,n-x+1)+(ll)fac[n-x+1]*C(n-2,n-x+2))%mod;
    25             ans=(ans-(ll)fac[x-3]*s%mod+mod)%mod;
    26         }
    27         printf("%d
    ",ans);
    28     }
    29     return 0;
    30 }
    View Code
  • 相关阅读:
    AngularJS开发指南6:AngularJS表单详解
    AngularJS开发指南5:AngularJS表达式详解
    AngularJS开发指南4:指令的详解
    grunt入门讲解7:项目脚手架grunt-init
    grunt入门讲解6:grunt使用步骤和总结
    grunt入门讲解5:创建插件,安装Grunt以及常见问题
    grunt入门讲解4:如何创建task(任务)
    grunt入门讲解3:实例讲解使用 Gruntfile 配置任务
    grunt入门讲解2:如何使用 Gruntfile 配置任务
    grunt入门讲解1:grunt的基本概念和使用
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15362876.html
Copyright © 2020-2023  润新知