• 51nod1934:受限制的排列 (分治+组合数)


    对于一个  11 到  nn 的排列  p1,p2,,pnp1,p2,⋯,pn ,我们可以轻松地对于任意的  1in1≤i≤n 计算出  (li,ri)(li,ri) ,使得对于任意的  1LRn1≤L≤R≤n 来说  min(pL,pL+1,,pR)=pimin(pL,pL+1,⋯,pR)=pi 当且仅当  liLiRrili≤L≤i≤R≤ri 。 

    给定整数  nn 和  (li,ri)(li,ri)   (1in)(1≤i≤n) ,你需要计算有多少种可能的  11 到  nn 的排列  p1,p2,,pnp1,p2,⋯,pn 满足上述条件。 

    由于答案可能很大,你只需要给出答案对  109+7109+7 取模的值。

     

    Input每个测试点包含多组测试数据,不超过 5000 组。 
    对于每组测试数据: 
    第一行包含一个正整数 n ,满足 1 ≤ n ≤ 10^6 。 
    第二行包含 n 个正整数 l_1, l_2, ..., l_n ,对于 i = 1, 2, ..., n 满足 1 ≤ l_i ≤ i 。 
    第三行包含 n 个正整数 r_1, r_2, ..., r_n ,对于 i = 1, 2, ..., n 满足 i ≤ r_i ≤ n 。 
    保证每个测试点的所有测试数据的 n 之和不超过 3*10^6 。 
    每个测试点的输入数据不超过 40MiB ,请做好读入优化。Output对于每组测试数据,输出一行"Case #x: y"(不含引号),其中 x 表示测试数据的编号(从 1 开始), y 表示这组数据的答案对 10^9+7 取模的值。Sample Input

    3
    1 1 3
    1 3 3

    Sample Output

    Case #1: 2

    思路:用solve(L,R)表示当前区间的排列方案数,显然最大的一个数贯穿整个区间,不难找到这个最大的数的位置pos,那么把最大的数安置在pos位置处,然后挑选pos-L个数到pos的左边,剩下的到右边,变为solve(L,pos-1)*solve(pos+1,R);

    (这里用map来找最大位置。普通的输入优化还是TEL

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int Mod=1e9+7;
    const int maxn=1000000;
    int L[maxn+10],pre[maxn+10],lat[maxn+10];
    int fac[maxn+10],rev[maxn+10],ans,N,Case=0;  ;
    map<pair<int,int>,int >mp;
    void read(int &x){
        x=0; char c=getchar();
        while(c>'9'||c<'0') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    }
    void solve(int l,int r)
    {
        if(l>r) return ;
        int pos=mp[make_pair(l,r)];
        if(pos>r||pos<l){ ans=0; return ;}
        ans=(ll)ans*fac[r-l]%Mod*rev[pos-l]%Mod*rev[r-pos]%Mod;
        solve(l,pos-1); solve(pos+1,r);
    }
    int main()
    {    
         
         fac[0]=1; for(int i=1;i<=maxn;i++) fac[i]=(ll)fac[i-1]*i%Mod;
         rev[1]=1; for(int i=2;i<=maxn;i++) rev[i]=(ll)(Mod-Mod/i)*rev[Mod%i]%Mod;
         rev[0]=1; for(int i=2;i<=maxn;i++) rev[i]=(ll)rev[i-1]*rev[i]%Mod;
         while(~scanf("%d",&N)){
             ans=1; mp.clear();
             for(int i=1;i<=N;i++) read(pre[i]);     
            for(int i=1;i<=N;i++) read(lat[i]);
            for(int i=1;i<=N;i++) mp[make_pair(pre[i],lat[i])]=i;
            solve(1,N);
            printf("Case #%d: %d
    ",++Case,ans);
         }
         return 0;
    }
  • 相关阅读:
    2020-2021-1 20209314《Linux内核原理与分析》第七周作业
    2020-2021-1 20209314《Linux内核原理与分析》第六周作业
    2020-2021-1 20209314《Linux内核原理与分析》第五周作业
    2020-2021-1 20209314《Linux内核原理与分析》第四周作业
    2020-2021-1 20209314《Linux内核原理与分析》第三周作业
    选做题MyOD 20209314
    2020-2021-1 20209314《Linux内核原理与分析》第二周作业
    2020-2021-1 20209322《Linux内核原理与分析》第十二周作业
    2020-2021-1 20209322《Linux内核原理与分析》第十一周作业
    2020-2021-1 20209322《Linux内核原理与分析》第九周作业
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9184982.html
Copyright © 2020-2023  润新知