您的位置:首页 > 其它

Codeforces Round #178 (Div. 2) C. Shaass and Lights 【组合数学】

2013-04-08 02:06 465 查看
http://codeforces.com/contest/294/problem/C

先考虑连续子集内的情况,如果有两边的情况,ans *=1 ;不然,设子集大小为n,ans*=2^(n-1)。

在自己间的组合问题,设每个子集大小为Ni(1<=i<=m),ans = ans * C(N1+...+Nm,N1) * C(N2+...+Nm,N2) * ... * C(N(m-1)+Nm,N(m-1)) * C(Nm,Nm)。

注意n == m的时候ans=1,因为空集也是一种情况。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
using namespace std;
template <class T> void checkmin(T &t,T x) {if(x < t) t = x;}
template <class T> void checkmax(T &t,T x) {if(x > t) t = x;}
template <class T> void _checkmin(T &t,T x) {if(t==-1) t = x; if(x < t) t = x;}
template <class T> void _checkmax(T &t,T x) {if(t==-1) t = x; if(x > t) t = x;}
typedef pair <int,int> PII;
typedef pair <double,double> PDD;
typedef long long ll;
#define foreach(it,v) for(__typeof((v).begin()) it = (v).begin(); it != (v).end ; it ++)
#define MOD 1000000007
ll mi(ll a , ll b) {
if(b == 0) return 1;
if(b == 1) return a % MOD;
ll t = 1;
if(b % 2 == 1) t = a;
ll tt = mi(a , b/2);
return ( ( tt * tt ) % MOD * t ) % MOD;
}
ll jc(ll a) {
ll b = a;
ll ans = 1;
while(b > 1) {
ans = (ans * b) % MOD;
b = b - 1;
}
return ans;
}
void gcd(ll a , ll b , ll &d , ll &x , ll &y) {
if(!b) {d = a; x = 1; y = 0;}
else { gcd(b , a%b,d,y , x); y -= x * (a/b); }
}
ll inv(ll a , ll n) {
ll d , x , y;
gcd(a , n , d,  x , y);
return d == 1 ? (x+n)%n : -1;
}
ll a[10100];
ll  b[10100];
int n , m , aa;
int cnt = 0;
int main() {
cin >> n >> m;
for(int i=0;i<m;i++) cin >> a[i];
if(n == m) { cout << "1" << endl; return 0; }
sort(a,a+m);
if(a[0] != 1) b[cnt++] = a[0] - 1;
for(int i=1;i<m;i++) {
ll del = a[i] - a[i-1] -1;
if(del <= 0) continue;
b[cnt++] = del;
}
if(a[m-1] != n) b[cnt++] = n - a[m-1];
ll ans = 1;
int start = 1;
if(a[0] == 1) start = 0;
int end = cnt-1;
if(a[m-1] == n) end = cnt;
for(int i=start;i<end;i++) ans = (ans * mi(2,b[i]-1)) % MOD;
ll mm = n - m;
for(int i=0;i<cnt-1;i++) {
ans = (ans * jc(mm) ) % MOD;
ll ggg = inv( jc(b[i]) , MOD );
ans = (ans * ggg) % MOD;
ggg = inv( jc(mm - b[i]) , MOD );
ans = (ans * ggg) % MOD;
mm -= b[i];
}
cout << ans << endl;
return 0;
}


求逆部分当时用的是刘汝佳老师《算法竞赛入门经典训练指南》上的模板
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: