标签:
题意:给出你多个区间,在给定的区间中选出至少k区间,算出它们相交后的区间大小。然后算出所有情况的和。
分析:把所有区间叠加起来,然后算出次数tk>=k的子区间的组合数C(tk,k),然后求和。
涉及的知识点:乘法逆元+离散化+(线段树)
代码1:(简单且快且需要空间少且代码短)
/************************************************ Author :DarkTong Created Time :2016/7/8 9:12:58 File Name :E_3.cpp *************************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> #define INF 0x3f3f3f3f #define esp 1e-9 typedef long long LL; using namespace std; const int maxn = 200000 + 10; const int MOD = 1e9+7; int l[maxn], r[maxn], sum[maxn*2], rec[maxn*2]; LL fac[maxn]; int quick(LL x, int n) { LL ans=1; if(x==0) return 0; while(n) { if(n&1)ans=(ans*x)%MOD; x=(x*x)%MOD; n>>=1; } return ans; } void init() { fac[0]=1; for(int i=1;i<maxn;++i) fac[i]=(fac[i-1]*i)%MOD; } int Inv(int n) { return quick(n, MOD-2); } LL Cnm(int n, int m) { return fac[n]*(Inv(fac[m]*fac[n-m]%MOD))%MOD; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); init(); int n, k, cnt=0; scanf("%d%d", &n, &k); for(int i=0;i<n;++i) { scanf("%d%d", &l[i], &r[i]); rec[cnt++]=l[i]; rec[cnt++]=++r[i]; } sort(rec, rec+cnt); cnt=unique(rec, rec+cnt)-rec; for(int i=0;i<n;++i) { int t; t = lower_bound(rec, rec+cnt, l[i])-rec; sum[t]++; t = lower_bound(rec, rec+cnt, r[i])-rec; sum[t]--; } int tk = sum[0], ans=0; for(int i=1;i<cnt;++i) { if(tk>=k) ans = (ans+Cnm(tk, k)*(rec[i]-rec[i-1])%MOD)%MOD; tk += sum[i]; } printf("%d\n", ans); return 0; }
代码2:(线段树-复杂且慢且需要空间多且代码长)
/************************************************ Author :DarkTong Created Time :2016/7/7 21:58:31 File Name :E_2.cpp *************************************************/ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> #define INF 0x3f3f3f3f #define esp 1e-9 typedef long long LL; using namespace std; const int maxn = 200000 + 100; const int MOD = 1e9+7; struct Node { int l, r, w, f; }a[maxn*16]; int n, k, l[maxn], r[maxn], tt[maxn*4]; map<int, int> id; LL fac[maxn]; void init() { fac[0]=1; for(int i=1;i<maxn;++i) fac[i]=(fac[i-1]*i)%MOD; } LL quick(LL x, int n) { LL ans = 1; if(x==0) return 0; while(n) { if(n&1)ans=(ans*x)%MOD; x=x*x%MOD; n>>=1; } return ans; } LL Inv(LL x) { return quick(x, MOD-2); } LL Cnm(LL n, LL m) { LL t = (fac[n]*Inv(fac[m]*fac[n-m]%MOD))%MOD; return t; } void PushDown(int th) { a[th<<1].w += a[th].w; a[th<<1|1].w+=a[th].w; a[th].w = 0; a[th<<1].f=a[th<<1|1].f=1; a[th].f = 0; } void Build(int th, int L, int R) { a[th].l=L; a[th].r=R; a[th].f=a[th].w=0; if(L+1==R) return; int m=(L+R)/2; Build(th<<1, L, m); Build(th<<1|1, m, R); } void Update(int th, int L, int R) { if(L<=a[th].l&&a[th].r<=R) { a[th].w++; a[th].f=1; return; } if(a[th].f) PushDown(th); int m=(a[th].l+a[th].r)/2; if(L<m&&m<=R)Update(th<<1, L, m); else if(L<m) Update(th<<1, L, R); if(L<=m&&m<R)Update(th<<1|1, m, R); else if(m<R) Update(th<<1|1, L, R); } LL Tra(int th, int L, int R) { if(L+1==R) { if(a[th].w>=k)return Cnm(a[th].w, k)*(tt[a[th].r]-tt[a[th].l])%MOD; else return 0; } if(a[th].f) PushDown(th); int m = (a[th].l+a[th].r)/2; LL ans=0; ans+=Tra(th<<1, L, m); ans+=Tra(th<<1|1, m, R); return ans%MOD; } int main() { init(); scanf("%d%d", &n, &k); int tl, tr, cnt=0; for(int i=0;i<n;++i) { scanf("%d%d", &tl, &tr); l[i]=tl; r[i]=tr; tt[cnt++]=tl; tt[cnt++]=tl+1; tt[cnt++]=tr; tt[cnt++]=tr+1; } //lisanhua sort(tt, tt+cnt); cnt = unique(tt, tt+cnt)-tt; for(int i=0;i<cnt;++i) id[tt[i]]=i; Build(1, 0, cnt-1); for(int i=0;i<n;++i) Update(1, id[l[i]], id[r[i]+1]); cout<<Tra(1, 0, cnt-1)<<endl; return 0; }
Codeforces 689E - Mike and Geometry Problem
标签:
原文地址:http://www.cnblogs.com/DarkTong/p/5653063.html