codeforces 1699 C. The Third Problem

 分析:

对于给定的一个序列,首先,我们可以确定哪些位置上的数是固定的,在固定的两个位置之间,station[i] , station[i + 1] ,我们必须要塞入大于max(val[station[i]] , val[station[i + 1]]) 的数才能满足题意,而塞入这些数的位置可以随机排列,因此,我们需要先写两个函数,一个是阶乘取模,另一个是组合数取模。

易错点:最后 答案method在循环过程中要注意取余数;

//阶乘取模代码:

int fac(int n){
	int f = 1;
    for(int i = 1; i <= n; i++){
    	f = ((f%mod)*(i%mod))%mod;
    }
    return f;
}

//组合数取模代码:

int collect(int n, int m){
  static int M = 0, inv[maxn], mul[maxn], invMul[maxn];
  while(M <= n){
    if(M){
      inv[M]=M==1?1:(mod - mod/M)*inv[mod%M]%mod;
      mul[M] = mul[M - 1]*M%mod;
      invMul[M] = invMul[M - 1]*inv[M]%mod;
    }else  mul[M] = 1, invMul[M] = 1;
    M++;
  }  
  return mul[n]*invMul[m]%mod*invMul[n - m]%mod;
}

//AC 代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define int long long
const int maxn = 2e6 + 120;
const int mod = 1e9 + 7; 
int a[maxn];
int hs[maxn];
int sh[maxn];
struct node{
  int station;
  int val;
}x[maxn];
int fac(int n){
	int f = 1;
    for(int i = 1; i <= n; i++){
    	f = ((f%mod)*(i%mod))%mod;
    }
    return f;
}
int collect(int n, int m){
  static int M = 0, inv[maxn], mul[maxn], invMul[maxn];
  while(M <= n){
    if(M){
      inv[M]=M==1?1:(mod - mod/M)*inv[mod%M]%mod;
      mul[M] = mul[M - 1]*M%mod;
      invMul[M] = invMul[M - 1]*inv[M]%mod;
    }else  mul[M] = 1, invMul[M] = 1;
    M++;
  }  
  return mul[n]*invMul[m]%mod*invMul[n - m]%mod;
}
signed main(){
   int t;
   cin>>t;
   while(t--){
       vector<int>ver;
       int n;
       cin>>n;
       for(int i = 1; i <= n; i++){
         cin>>a[i];
         hs[a[i]] = i;
       }
      x[0].val = 0;
      x[0].station = hs[0];
      sh[0] = 0;     ver.push_back(0);
      int left = x[0].station;
      int right = x[0].station;
      int cnt1 = -1;
      int cnt2 = 0;
      for(int i = 1; i <= n - 1; i++){
         if(hs[i] < left){
             left = hs[i];
             cnt2 = cnt2 + 2;
             x[cnt2].val = i;    x[cnt2].station = hs[i];
             sh[i] = cnt2;     ver.push_back(i);
         }else if(hs[i] > right){
             right = hs[i];
             cnt1 = cnt1 + 2;
             x[cnt1].val = i;    x[cnt1].station = hs[i];
             sh[i] = cnt1;     ver.push_back(i);
         }
      }
      int remain = n - ver.size();  
      int sl = 0;   int method = 1;
      for(int i = ver.size() - 1; i >= 1; i--){
         int a = sh[ver[i]];
         int minx = 0;
         int b = max(minx, sh[ver[i]] - 2);
         int num;
         if(sh[ver[i]]%2 == 0){
             num = x[b].station - x[a].station - 1;
 
         }else{
         	num = x[a].station - x[b].station - 1;
         }    
         //cout<<n - 1 - ver[i] - sl<<" "<<num<<" "<<collect(n - 1 - ver[i] - sl, num)<<" "<<fac(num)<<endl;
         method = ((method%mod)*(collect(n - 1 - ver[i] - sl, num)%mod))%mod;
         method = ((method%mod)*(fac(num)%mod))%mod;
         sl = sl + num + 1;
      }
      cout<<method<<endl;
   }    
    
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值