CF316D2 PE Lesson
题意描述
翻译的有些歧义......
给定
n 个人,每个人有一个球,每个人的球互不相同,每个人可以交换a_i 次球(也可以不交换),求最终球的排列方案数。
做法思路
首先,将两个人交换不会影响最终的答案。故将所有只能交换一次的全部放到最左边不会影响答案。设其共有
首先考虑
每个人的交换有两种可能:
- 不交换(自己和自己交换)
- 和之前的一个人交换。
放到式子上来,设
考虑加上
由于可以交换两次的人不好处理,考虑让他们先交换。
那么第一个人可以与
考虑这样交换后还有多少个人能交换。
通过统计贡献的方式可以轻松得到:
原来共可以交换
那么可以轻松得到答案为
代码实现
代码就非常简单了......
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
x=0;
char ch=getchar();
bool fl=0;
while(ch<'0'||ch>'9') fl=(fl||ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+(ch^'0'),ch=getchar();
x=fl?-x:x;
}
template<typename T>void prt(T x){
if(x>9) prt(x/10);
putchar(x%10+'0');
}
template<typename T>inline void put(char ch,T x){
if(x<0) putchar('-'),x=-x;
prt(x);
putchar(ch);
}
inline void putstr(string s){
for(int i=0;i<(int)s.length();i++) putchar(s[i]);
}
#define mod 1000000007
int n,s,f[2],ans;
inline int add(int a,int b){
if(a+b>=mod) return a+b-mod;
return a+b;
}
inline int mul(int a,int b){
return (long long)a*b%mod;
}
int main(){
read(n);
for(int i=1,x;i<=n;i++) read(x),s+=x==1;
f[0]=f[1]=1;
for(int i=2;i<=s;i++)
f[i&1]=add(mul(f[i&1],i-1),f[(i&1)^1]);
ans=f[s&1];
for(int i=n;i>s;i--) ans=mul(ans,i);
put('\n',ans);
return 0;
}