• HDU 6044 Limited Permutation(2017多校)【计数 快速读入挂 线性逆元】


    题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6044

    题意:

    对于有n个元素的全排列的合法性定义为:有n个区间,对于第i个区间[li,ri]有li<=i<=ri,对于任意1<=L<=i<=R<=n,当前仅当li<=L<=i<=R<=ri时P[i]=min(P[L],P[L+1],...,P[R])。

    求排列的合法方案数;

    解题思路:

    大佬讲的很清楚了:https://blog.csdn.net/qq_31759205/article/details/76146845

    前期技能:

    ①快速读入挂

    ②线性求阶乘逆元

    为什么这样排序之后 dfs 一定是合理的呢?

    因为题目给出的是 N 个区间, 每个区间对应一个值,因为每个区间的合法定义都是唯一的,

    也就是说序列中的每一个值其实对应一个区间,所以dfs区间是合理的,如果区间出现不合法的情况则说明无解。

    AC code:

     1 #include <bits/stdc++.h>
     2 #define INF 0x3f3f3f3f
     3 #define LL long long
     4 using namespace std;
     5 const int MAXN = 1e6+10;
     6 const LL mod = 1e9+7;
     7 LL fac[MAXN], Inv[MAXN];
     8 
     9 namespace IO{
    10     const int MAX = 4e7;
    11     char buf[MAX]; int c, sz;           //预先缓冲到数组buf
    12     void begin(){
    13         c = 0;
    14         sz = fread(buf, 1, MAX, stdin);
    15     }
    16     inline bool read(int &t){
    17         while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
    18         if(c >= sz) return false;
    19         bool flag = 0; if(buf[c] == '-') flag = 1, c++;
    20         for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t*10+buf[c]-'0';
    21         if(flag) t=-t;
    22         return true;
    23     }
    24 }
    25 
    26 void Init()                                 //预处理排列数和逆元
    27 {
    28     fac[0] = Inv[0] = fac[1] = Inv[1] = 1;
    29     for(int i = 2; i < MAXN; i++) fac[i] = fac[i-1]*i%mod;
    30     for(int i = 2; i < MAXN; i++) Inv[i] = (mod-mod/i)*Inv[mod%i]%mod;
    31     for(int i = 2; i < MAXN; i++) Inv[i] = Inv[i]*Inv[i-1]%mod;
    32 }
    33 
    34 LL C(LL n, LL m)                            //计算组合数
    35 {
    36     return fac[n]*Inv[m]%mod*Inv[n-m]%mod;
    37 }
    38 
    39 struct Node
    40 {
    41     int l, r;
    42     int id;
    43 }a[MAXN];
    44 
    45 bool cmp(const Node s1, const Node s2)
    46 {
    47     if(s1.l == s2.l) return s1.r > s2.r;
    48     return s1.l < s2.l;
    49 }
    50 int ii;
    51 LL dfs(int L, int R)
    52 {
    53     if(a[ii].l != L || a[ii].r != R) return 0;
    54     int mid = a[ii++].id;
    55     LL fL = 1LL, fR = 1LL;
    56     if(L <= mid-1) fL = dfs(L, mid-1);      //左区间方案数
    57     if(R >= mid+1) fR = dfs(mid+1, R);      //右区间方案数
    58     LL cc = C(R-L, mid-L);
    59     return fL*fR%mod*cc%mod;
    60 }
    61 
    62 int main()
    63 {
    64     Init();
    65     int N, Case = 1;
    66     IO::begin();
    67     while(IO::read(N)){
    68         for(int i = 1;i <= N; i++) IO::read(a[i].l);
    69         for(int i = 1;i <= N; i++) IO::read(a[i].r), a[i].id = i;
    70         sort(a+1, a+1+N, cmp); ii = 1;
    71         LL ans = dfs(1, N);
    72         printf("Case #%d: %lld
    ", Case++, ans);
    73     }
    74     return 0;
    75 }
    View Code
  • 相关阅读:
    安装 oracle
    svn 编辑
    软件构架
    liunx操作
    css的样式分类
    简单自己做了一个个人简历
    网页制作之表格,列表
    MYSQL表创建
    linux操作指令 第二部分
    linux操作指令 第一部分
  • 原文地址:https://www.cnblogs.com/ymzjj/p/10804618.html
Copyright © 2020-2023  润新知