18.10.17队测

T1 :

题意简化 : 给出(n)个区间和(m)个点,问一个区间和一个点匹配,最多可以匹配多少个点。 其中,(nleq 2e5,mleq2e5,a[i]leq1e9).

贪心,给点排序,然后把区间以右端点为关键字用一个set维护,每次对于一个点取右端点大于且最靠近这个点的区间。

#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define write(x) printf("%d
",x)
#define maxn 200005
#define inf 1e9
int n,m,a[maxn],ans;
struct data{int x,y;}c[maxn];
multiset<int > s;
multiset<int> :: iterator x;
bool cmp(data a,data b){return (a.y==b.y&&a.x<b.x)||a.y<b.y;}
int main(){
    read(n),read(m);
    for(int i=1;i<=m;i++) read(c[i].x),read(c[i].y);
    for(int i=1;i<=n;i++) read(a[i]),s.insert(a[i]);
    sort(c+1,c+m+1,cmp);s.insert(inf);
    for(int i=1;i<=m;i++){
    	x=s.lower_bound(c[i].x);
    	if((*x)<=c[i].y&&x!=s.end()) ans++,s.erase(x);
    }
    write(ans);
    return 0;
}

T2 :

题意简化: 问随机的树在模(p)的期望深度。构造方法:每次将第(i)个点在([1,i-1])中随机的选一个点作为父亲。

其中:(nleq 200,pleq1e9+7),且(p)为质数。

对于(50\%)的数据,(nleq20),可以状压dp,设(f[sta])为状态为(sta)的方案数。

对于状态的记录,首先可以想到:第(i)位为(h)表示第(i)个点的高度是(h),但是这样不方便我们记录,所以将这个数列排序后差分一下,可以得到一个(01)串,然后状态转移可以类似的由(1001001)转移到(10001001)(10010001)等。

对于所有数据,显然不能用上面的指数级dp。记(dp[i][j])表示(i)个结点的森林深度为(j)的概率。

[dp[i][j]=dp[i-1][j-1]*(j-1)*inv[i]+dp[i-1][j]*(i-j)*inv[i] ]

其中,由于一个点也是一棵树,可以单独存在,所以要除以(i)而不是(i-1)

然后记(f[i][j])表示i个点的树深度小于等于j的概率,(g[i][j])为i个点的森林深度小于等于j的概率。

首先,显然(f[i ][ j ]=g[i-1][j-1]) ,因为可以设一个根节点连向森林里的所有树,然后深度(+1).然后,

[g[i][j]=sum_{k=1}^if[k][j]*g[i-k][j]*dp[i][k] ]

这个也比较显然,然后最后对于深度为i的概率可以由(f[n][i]-f[n][i-1])得到。

初值以及小细节什么的看代码吧。。说实话这个dp是真的难想到。。

#pragma GCC optimize(3)
#include<cstdio>
#define int long long
#define max(a,b) (a<b?b:a)
#define min(a,b) (a<b?a:b)
#define swap(x,y) x^=y^=x^=y
#define isdigit(ch) (ch>='0'&&ch<='9')
#define abs(x) (x<0?-x:x)
#define base 2333
#define pb push_back
inline void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
}
inline void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
inline void write(int x) {print(x);puts("");}
#define maxn 230
int dp[maxn][maxn],g[maxn][maxn],f[maxn][maxn],n,p,inv[maxn];
signed main() {
    read(n),read(p);inv[1]=1;inv[0]=1;
    for(int i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p;
    dp[1][1]=1;
    for(int i=2;i<=n;i++)
    for(int j=1;j<=n;j++)
        dp[i][j]=(dp[i-1][j-1]*(j-1)%p*inv[i]%p+dp[i-1][j]*(i-j)%p*inv[i]%p)%p;
    for(int i=0;i<=n;i++) f[1][i]=g[1][i]=f[0][i]=g[0][i]=1;g[1][0]=0;
    for(int i=2;i<=n;i++)
    for(int j=1;j<=n;j++) {
        f[i][j]=g[i-1][j-1];
        for(int k=1;k<=i;k++) (g[i][j]+=f[k][j]*g[i-k][j]%p*dp[i][k])%=p;
    }
    int ans=0;
    for(int i=1;i<=n;i++) ans=(ans+i*(f[n][i]-f[n][i-1]))%p;
    write((ans-1+p)%p);
    return 0;
}

T3 :

题意简述 :

给出一颗有编号的树,每次选择一个区间的编号,问有多少个联通块。

其中(nleq 2e5,qleq2e5).

(nleq2000)暴力有50分。。

其实这题和树一点关系也没有。。。

可以发现,对于一个区间([l,r]),先令(ans=r-l+1),当且仅当一条边(<u,v>(u<v)) 满足(lleq u,vleq r)时,才可以令(ans--).

于是这就变成了一个基本的二维偏序问题。。用个树状数组或者什么的维护下就好了。

#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
using std :: sort;
#define max(a,b) (a<b?b:a)
#define min(a,b) (a<b?a:b)
#define swap(x,y) x^=y^=x^=y
#define isdigit(ch) (ch>='0'&&ch<='9')
#define abs(x) (x<0?-x:x)
#define pb push_back
const int mod = 1e9+7;
inline void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
}
inline void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
inline void write(int x) {print(x);puts("");}
#define maxn 2000050
 
int n,q;
struct node {int l,r,x,ans,id;}a[maxn];
struct binary_index_tree {
    int tree[maxn];
    void modify(int x,int v) {for(int i=x;i<=n;i+=i&-i) tree[i]+=v;}
    int query(int x,int ans=0) {for(int i=x;i;i-=i&-i) ans+=tree[i];return ans;}
}T;
int cmp_l(node aa,node b) {return aa.l<b.l||(aa.l==b.l&&aa.r>b.r)||(aa.l==b.l&&aa.r==b.r&&aa.x>b.x);}
int cmp_id(node aa,node b) {return aa.id<b.id;}
 
int main() {
    read(n),read(q);
    for(int i=1;i<n;i++) {read(a[i].l),read(a[i].r),a[i].x=1;if(a[i].l>a[i].r) swap(a[i].r,a[i].l);}
    for(int i=n;i<=n+q-1;i++) read(a[i].l),read(a[i].r),a[i].x=2,a[i].ans=a[i].r-a[i].l+1,a[i].id=i;
    sort(a+1,a+n+q,cmp_l);
    for(int i=n+q-1;i;i--) {
    if(a[i].x==1) T.modify(a[i].r,1);
    else a[i].ans-=T.query(a[i].r);
    }
    sort(a+1,a+n+q,cmp_id);
    for(int i=n;i<n+q;i++) write(a[i].ans);
    return 0;
}
原文地址:https://www.cnblogs.com/hbyer/p/9806905.html