U168834 [NOI2021SDPT3Test2]体育测试
首先考虑全部都是正的怎么做。
直接排个序,排列组合即可。
但此时加入了负数,这就比较难处理。
考虑容斥:
先把所有负数取绝对值,当上标记,然后升序排序(若数大小相同,负的排在前面)。
定义状态 \(f_{i,j}\) 表示前 \(i\) 个数,钦定 \(j\) 个负数不满足的方案数。
为方便转移,定义 \(c_i\) 表示前 \(i\) 个数中有多少个负的。
考虑转移:
- 若当前为正数,则有 \(f_{i,j} = f_{i-1,j} \cdot (a_i-i-j+c_i+1)\).
- 若当前为负数,则有 \(f_{i,j} = f_{i-1,j} + f_{i-1,j-1} \cdot(a_i-i-j+c_i)\).
答案显然为 \(\sum_{i=0}^{c_n}(-1)^i \cdot f_{n,i} \cdot (c_n-i)\).
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e3+5,mod = 1e9+7;
struct node{
ll x;
int op;
bool operator<(node b)const{
if(x!=b.x)return x<b.x;
return op>b.op;
}
}a[N];
int n;
int c[N];
ll fac[N];
ll f[N][N];
int main() {
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x;
if(a[i].x<0)a[i].op=1,a[i].x=-a[i].x;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) {
if(a[i].op)c[i]=1;
c[i]+=c[i-1];
}
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=fac[i-1]*i%mod;
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=c[i];j++){
if(a[i].op==0)f[i][j]=f[i-1][j]*max(0ll,a[i].x-i-j+c[i]+1)%mod;
else {
f[i][j]=f[i-1][j];
if(j)f[i][j]=(f[i][j]+f[i-1][j-1]*max(0ll,a[i].x-i-j+c[i])%mod)%mod;
}
}
}
ll ans=0;
for(int i=0;i<=c[n];i++){
// cout<<f[n][i]<<" \n"[i==c[n]];
if(i&1)ans=(ans-f[n][i]*fac[c[n]-i]%mod+mod)%mod;
else ans=(ans+f[n][i]*fac[c[n]-i]%mod)%mod;
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号