• [CSP-S模拟测试74]题解


    A.梦境

    如果不用去重一定要用Multiset……挂30分算是出题人手下留情了。

    贪心。把点排序,区间按右端点递增排序。依次考虑每个区间,取能选的最靠左的点即可。multiset维护。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<set>
    #include<algorithm>
    using namespace std;
    int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    const int N=2e5+5;
    int n,m,t[N],vis[N],ans;
    struct inv
    {
    	int l,r;
    	friend bool operator < (const inv &x,const inv &y)
    	{
    		return x.r<y.r;
    	}
    }a[N];
    multiset<int> s;
    multiset<int>::iterator it1,it2;
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		a[i].l=read(),a[i].r=read();
    	for(int i=1;i<=m;i++)
    		t[i]=read();
    	sort(t+1,t+m+1);
    	for(int i=1;i<=m;i++)
    		s.insert(t[i]);
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;i++)
    	{
    		if(s.empty())break;
    		it1=s.lower_bound(a[i].l);
    		it2=s.upper_bound(a[i].r);
    		if(it1==s.end())continue;
    		if(it2!=s.begin())it2--;
    		else continue;
    		if((*it1)>(*it2))continue;
    		ans++;
    		s.erase(it1);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    B.玩具

     让我懒癌发作的神dp

    注意问题的转化方式以及辅助数组的正确使用姿势。

    比较难的计数往往需要探究已给出条件的一些性质,并把抽象的转移过程具体化。本题的$f[i][j]=g[i-1][j-1]$就是一个很好的例子。

    还有就是状态的正确设定,计数一般不会有特别鬼畜的转移方式,所以状态数组的含义十分重要。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=205;
    ll n,mod;
    ll dp[N][N],g[N][N],f[N][N],inv[N];
    // dp:in the 1st tree
    // f:tree's depth <=j
    // g:forest's depth <=j
    ll qpow(ll a,ll b)
    {
        ll res=1;a=a%mod;
        while(b)
        {
            if(b&1)res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    int main()
    {
        scanf("%lld%lld",&n,&mod);
        dp[1][1]=f[1][0]=1;
        for(int i=1;i<=n;i++)
            inv[i]=qpow(i,mod-2);
        for(int i=2;i<=n;i++)
            for(int j=1;j<=i;j++)
                dp[i][j]=(dp[i-1][j-1]*1LL*(j-1)%mod*inv[i]%mod+dp[i-1][j]*1LL*(i-j)%mod*inv[i]%mod)%mod;
        for(int i=0;i<=n;i++)
            g[0][i]=1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=n;j++)
            {
                if(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]%mod*dp[i][k]%mod)%=mod;
            }
        ll ans=0;
        for(int i=1;i<=n;i++)
            (ans+=(f[n][i]-f[n][i-1]+mod)%mod*i%mod)%=mod;
        cout<<ans<<endl;
        return 0;
    }
    

    C.飘雪圣域

    森林的联通块个数=点数-边数,记住了!!

    上次考场能YY出来这次却想不到QAQ……

    那么对于每次询问,点数已知,只需要求出这些点之间有多少边即可。

    设一条边连接了$x$和$y$。那么把边排序,以$x$为下标把$y$上传到主席树上,每次查询区间有多少数 $leq y$即可。

    连图都不用建2333

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    
    const int N=2e5+5;
    int n,Q;
    struct edge
    {
        int x,y;
        friend bool operator < (const edge &a,const edge &b)
        {
            return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
        }
    }e[N<<1];
    int root[N<<5],ls[N<<5],rs[N<<5],size[N<<5],pos[N],type;
    void update(int &k,int l,int r,int old,int val)
    {
        k=++type;
        ls[k]=ls[old];rs[k]=rs[old];
        size[k]=size[old]+1;
        if(l==r)return ;
        int mid=l+r>>1;
        if(val<=mid)update(ls[k],l,mid,ls[old],val);
        else update(rs[k],mid+1,r,rs[old],val);
    }
    int query(int k,int l,int r,int val)
    {
        if(l==r)return size[k];
        int mid=l+r>>1;
        if(val<=mid)return query(ls[k],l,mid,val);
        else return size[ls[k]]+query(rs[k],mid+1,r,val);
    }
    int main()
    {
        n=read();Q=read();
        for(int i=1;i<n;i++)
        {
            int x=read(),y=read();
            e[i]=(edge){min(x,y),max(x,y)};
        }
        sort(e+1,e+n);
        for(int i=1;i<n;i++)
        {
            update(root[i],1,n,root[i-1],e[i].y);
            if(!pos[e[i].x])pos[e[i].x]=i;
        }
        pos[n]=n;root[n]=root[n-1];
        for(int i=n;i;i--)
            if(!pos[i])pos[i]=pos[i+1];
        while(Q--)
        {
            int l=read(),r=read();
            int lc=pos[l],rc=pos[r];
            int num=query(root[rc],1,n,r)-query(root[lc-1],1,n,r);
            printf("%d
    ",r-l+1-num);
        }
        return 0;
    }
    
  • 相关阅读:
    Delphi的对话框窗体
    Delphi中窗体的事件
    TForm类有关属性简介
    Delphi的工具栏
    一个简单的MDI示范程序(Delphi)
    Delphi的组件选项卡(Component Palette)
    最简单的多重窗体的应用(Delphi)
    发现一个SVG做的地图网站:ChinaQuest
    计算最近点和最近线段
    寻找MapBar的地图切割方法
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11679411.html
Copyright © 2020-2023  润新知