CodeForces 316D3 PE Lesson [DP+Math]

D3. PE Lesson
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Smart Beaver decided to be not only smart, but also a healthy beaver! And so he began to attend physical education classes at school X. In this school, physical education has a very creative teacher. One of his favorite warm-up exercises is throwing balls. Students line up. Each one gets a single ball in the beginning. The balls are numbered from 1 to n (by the demand of the inventory commission).

Figure 1. The initial position for n = 5.

After receiving the balls the students perform the warm-up exercise. The exercise takes place in a few throws. For each throw the teacher chooses any two arbitrary different students who will participate in it. The selected students throw their balls to each other. Thus, after each throw the students remain in their positions, and the two balls are swapped.

Figure 2. The example of a throw.

In this case there was a throw between the students, who were holding the 2-nd and the 4-th balls. Since the warm-up has many exercises, each of them can only continue for little time. Therefore, for each student we know the maximum number of throws he can participate in. For this lessons maximum number of throws will be 1 or 2.

Note that after all phases of the considered exercise any ball can end up with any student. Smart Beaver decided to formalize it and introduced the concept of the "ball order". The ball order is a sequence of n numbers that correspond to the order of balls in the line. The first number will match the number of the ball of the first from the left student in the line, the second number will match the ball of the second student, and so on. For example, in figure 2 the order of the balls was (12345), and after the throw it was (14325). Smart beaver knows the number of students and for each student he knows the maximum number of throws in which he can participate. And now he is wondering: what is the number of distinct ways of ball orders by the end of the exercise.


题意:

N个人站在一条线上传球,每个人传球次数的上限为Ai(值为1或者2),一开始每个人手上的球从左往右标为1..N,每一次传球,即是两个人手上的球互换,问传球后的所有的情况数(即最后产生的1-N的不同排列数)

范围:

N<=100W

解法:

对于所有人如果传球次数上限都为1的方案数话,是很容易想到dp方程的:F[I]=F[I-1]+(I-1)*F[I-2],即多出一个球不动或者从前面选一个交换。

如果有人传球次数上限为2的话,设1的数量为a,2的数量为b,那么先让这些次数为2的人先传一次,第一个人的选择数为b,第二个人的选择数为b-1,以此类推……最后发现正好剩下a个人的传球次数都为1,那么答案便是:

F[a]*b*b-1*b-2*……b-a+1

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;


ll mod=1000000007LL;
ll f[1001000];
void init(){
    f[0]=1;
    f[1]=1;
    f[2]=2;
    rep(i,3,1000000){
        f[i]=(f[i-1]+ll(i-1)*f[i-2])%mod;
    }
}
int _1,_2,n;
main(){
    init();
    scanff(n);
    rep(i,1,n){
        int x;
        scanff(x);
        if(x==1)_1++;
        else _2++;
    }
    ll ans=1;
    rep(i,1,_2){
        ans=(ans*ll(n-i+1))%mod;
    }
    ans=(ans*f[_1])%mod;
    printf("%lld\n",ans);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值