题目链接:HDU - 6044 - Limited Permutation
放一个博客:HDU-6044 (计数) - 十分残念的博客 - CSDN博客
题意是给定
n
个区间
对于一个区间
[li,ri]
,
pi
是其中最小的数,因此区间还可分为
[li,i−1]
和
[i+1,ri]
,其中
pj
和
pk
分别为其中最小的数字。
因此将所有区间按
li
递增,
ri
递减的顺序排序。第一个区间一定要是
[1,n]
,然后可以分成区间
[1,i−1]
和
[i+1,n]
,其中
[1,i−1]
是第
i+1
个区间,然后继续递归下去。(这种递归过程形象的看就像是在线段树上进行先序遍历)。
然后将数字进行分配。
假设
f(i)
为第
i
个区间的方案数,那么
答案为
f([1,n])
。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1e6+7;
int n;
ll frac[N],inv[N];
struct Seg
{
int l,r,id;
bool operator < (const Seg& t) const
{
return l<t.l||(l==t.l&&r>t.r);
}
}seg[N];
namespace IO {
const int MX = 4e7;
char buf[MX]; int c, sz;
void begin() {
c = 0;
sz = fread(buf, 1, MX, stdin);
}
inline bool read(int &t) {
while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
if(c >= sz) return false;
bool flag = 0; if(buf[c] == '-') flag = 1, c++;
for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t * 10 + buf[c] - '0';
if(flag) t = -t;
return true;
}
}
int cur;
bool ok;
ll power(ll a, ll b)
{
ll c=1;
while(b)
{
if(b&1) c=c*a%mod;
a=a*a%mod;
b>>=1;
}
return c;
}
void init()
{
frac[0]=1;
for(int i=1;i<N;++i) frac[i]=frac[i-1]*i%mod;
for(int i=1;i<N;++i) inv[i]=power(frac[i],mod-2);
}
ll C(ll n, ll m)
{
if(m==0||m==n) return 1;
return frac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll dfs(int l, int r)
{
if(!ok) return 0;
if(l>r) return 1;
if(seg[cur].l!=l||seg[cur].r!=r)
{
ok=false;
return 0;
}
int id = seg[cur++].id;
ll res=dfs(l,id-1)*dfs(id+1,r)%mod*C(r-l,id-l)%mod;
return res;
}
int main()
{
int T=1;
init();
IO::begin();
while(IO::read(n))
{
for(int i=0;i<n;++i)
IO::read(seg[i].l);
for(int i=0;i<n;++i)
IO::read(seg[i].r),seg[i].id=i+1;
sort(seg,seg+n);
cur=0;
ok=true;
printf("Case #%d: %I64d\n",T++,dfs(1,n));
}
return 0;
}