1. 程式人生 > >51nod1667 概率好題

51nod1667 概率好題

考慮計算方案數,令xi=aili(0xirili),得到

l1+x1?r2x2x1+x2?r2l1
x1x2並沒有本質差別,用插板法解決。取等號時可以直接算,取小於等於時可以加入一個元素來放置多出來的部分。上限用容斥來解決。
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=20,p=1000000007;
int l1[maxn],l2[maxn],r1[maxn],r2[maxn],f[maxn],fac[maxn+10
],inv[maxn+10],n1,n2,n; int inc(int x,int y) { x+=y; return x>=p?x-p:x; } int dec(int x,int y) { x-=y; return x<0?x+p:x; } int pow(int b,int k) { int r=1; for (;k;k>>=1,b=(LL)b*b%p) if (k&1) r=(LL)r*b%p; return r; } int get(int n,int m) { int ret=1
; for (int i=n+m-1;i>=n+1;i--) ret=(LL)ret*i%p; ret=(LL)ret*inv[m-1]%p; return ret; } int calc(int n,int s) { int ret=0,s1,cnt,x; for (int S=0;S<(1<<n);S++) { cnt=0; s1=s; for (int i=0;i<n;i++) if (S&(1<<i)) { cnt++; s1-=f[i]+1
; } if (s1<0) continue; x=get(s1,n); if (cnt&1) ret=dec(ret,x); else ret=inc(ret,x); } return ret; } void solve() { int x,y,z,w,s=1; scanf("%d",&n1); for (int i=1;i<=n1;i++) scanf("%d%d",&l1[i],&r1[i]); scanf("%d",&n2); for (int i=1;i<=n2;i++) scanf("%d%d",&l2[i],&r2[i]); n=n1+n2; w=0; for (int i=1;i<=n1;i++) w=dec(w,l1[i]); for (int i=1;i<=n2;i++) w=inc(w,r2[i]); for (int i=1;i<=n1;i++) f[i-1]=r1[i]-l1[i]; for (int i=1;i<=n2;i++) f[i+n1-1]=r2[i]-l2[i]; y=calc(n,w); f[n]=w; x=calc(n+1,w); for (int i=0;i<n;i++) s=(LL)s*(f[i]+1)%p; z=dec(s,x); x=dec(x,y); s=pow(s,p-2); x=(LL)x*s%p; y=(LL)y*s%p; z=(LL)z*s%p; printf("%d %d %d\n",z,y,x); } int main() { //freopen("a.in","r",stdin); fac[0]=1; for (int i=1;i<=maxn;i++) fac[i]=(LL)fac[i-1]*i%p; for (int i=0;i<=maxn;i++) inv[i]=pow(fac[i],p-2); int T; scanf("%d",&T); while (T--) solve(); }