zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    函数式宏定义与普通函数
    linux之sort用法
    HDU 4390 Number Sequence 容斥原理
    HDU 4407 Sum 容斥原理
    HDU 4059 The Boss on Mars 容斥原理
    UVA12653 Buses
    UVA 12651 Triangles
    UVA 10892
    HDU 4292 Food
    HDU 4288 Coder
  • 原文地址:https://www.cnblogs.com/hbyer/p/9806905.html
Copyright © 2011-2022 走看看