题意: 这儿共有n堆稻谷,编号为1到n。Psyche需要将这些谷堆以某种顺序排列,设最终排在第i位的谷堆是Ai。 她得知了一些该排列的要求: 1. 对于任意整数i∈[1,n],A1,A2,...,Ai的最小值为Bi。 2. 对于任意整数i∈[1,n],A1,A2,...,Ai的最大值为Ci。 现在Psyche想知道,共有多少种合法的排列。由于答案可能很大,输出时对998244353取模。思路:
这里是让求排列的个数,所谓排列就是每个数不可以重复出现。
由第一个条件得知 B[i] 是一个单调不递增序列。
求第二个条件得知 C[i] 是一个单调不递减序列。
然后得知B[0] == c[0] ==A[ 0 ];
不满足就无解。
然后我们再分析如果Bi<Bi−1,Ai=Bi;如果Ci>Ci−1,Ai=Ci。但是如果Bi<Bi−1和Ci>Ci−1同时满足,就会产生冲突导致无解。
然而当B[i-1]>B[i]&& C[i-1]==C[i] 时 可以唯一的确定A[i]=B[i];
当B[i-1]==B[i]&& C[i-1] < C[i] 时 可以唯一的确定A[i]=C[i];
当B[i-1]==B[i]&& C[i-1] == C[i] 时 可以确定 A[i]一定在区间( B[i],C[i]) 之间,
(这个区间正好满足取值范围的最小值与最大值)
因为是排列需要把以前用过的个数去掉就可以表示A[i]这个位置一共可以取值的个数。
把每个位置的可取值的个数相乘就可以了
#include<bits/stdc++.h>
#define LL long long
#define bug puts("*********")
#define INF 0x3f3f3f3f
using namespace std;
const int N=110000;
const LL mod=998244353;
int b[N];
int c[N];
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
for(int i=1;i<=n;i++){
scanf("%d",&c[i]);
}
if(c[0]!=b[0]){
puts("0");
continue;
}
int flag=0;
LL ans=1;
for(int i=2;i<=n;i++){
if(b[i-1]<b[i]||c[i-1]>c[i]){
flag=1;break;
}
if(b[i-1]>b[i]&&c[i-1]<c[i]){
flag=1;break;
}
if(b[i-1]==b[i]&&c[i-1]==c[i]){
ans=ans*(c[i]-b[i]-(i-2))%mod; ///c[i]-b[i]表示在这个范围内可以用多少个数用于填补a[i],i-2表示前面用去的个数。
}
}
if(flag)puts("0");
else printf("%lld\n",ans);
}
return 0;
}
<Bi−1
,