zoukankan      html  css  js  c++  java
  • 牛客 Wannafly 挑战赛26D 禁书目录 排列组合 概率期望

    原文链接https://www.cnblogs.com/zhouzhendong/p/9781060.html

    题目传送门 - NowCoder Wannafly 26D

    题意

      放一放这一题原先的题面:

    阿尔法城

    空间限制 512MB
    时间限制 2s

    题目描述

    听说遥远的α城里神仙题横行,毒瘤题占道,zzd 决定来送一道温暖。

    zzd 现在正距离α城很远处(可以理解成无穷远),通过望远镜看到了 α 城里的景象。

    α城中有 n 座高楼,排成一条直线,其中第 i 座高楼的高度为 a[i] ,颜色为 c[i] 。任意两个高楼不同,即使他们的高度和颜色都相同。

    zzd 惊喜地发现这些高楼排成的直线恰好与 zzd 的视线重合,且离 zzd 最近的是第 1 座高楼。

    如果一座大楼之前没有高度不小于它的高楼遮挡,那么 zzd 就能看见它。于是 zzd 很快就数出了他看到的颜色种数。

    α城里的神仙陈老爷想要阻止 zzd 送温暖,立马联合神仙 cly 发动了魔法:不断将高楼重新排列。

    这么多的变换,让 zzd 眼花缭乱。于是,zzd 决定,在去找 Mangoyang 并对陈老爷实施 α 行动之前,先问问你:对于所有排列,zzd 看到的颜色种数之和为多少?

    答案对 998244353 取模。

    输入描述

    第一行一个整数 n 。
    接下来 n 行,每行两个整数 a[i] 和 c[i] 。
    1<=n<=500000,
    1<=a[i],c[i]<=100000000

    输出描述

    一个整数,表示答案对 998244353 取模后的值。

    示例
    输入1
    4
    1 5
    4 3
    5 2
    3 1

    输出1
    50

    输入2
    10
    5 6
    1 2
    2 2
    10 9
    10 7
    8 6
    10 6
    1 2
    1 1
    8 3

    输出2
    6664320

      不过后来由于 ACM 赛制,样例 2 就没了。

    题解

      首先我们把这个总方案数转化成期望。

      根据期望的线性性,总答案可以分解成各个颜色被看见的概率之和。

      现在考虑如何求一个颜色被看见的概率。

      这里有一个结论——

    如果对于一个楼,高度不低于它的(包括它自己)有 $t$ 个,那么它被看见的概率就是 $frac 1t$ 。

      (证明:将当前楼插入比他高的楼的空隙中,有 $t$ 个方法,但是只有插在最前面的是能看见的)

      那么,一种颜色被看见的概率就是 $1-$ 每一个楼都没被看见的概率。注意到可能存在同种颜色有多个相同高度的楼的情况,需要将上面的结论升级一下——

    对于 $k$ 个相同高度的楼,如果高度不低于他们的楼有 $t$ 个,则他们中至少一个被看见的概率就是 $frac kt$ 

      (证明基于之前的结论,推导一下即可)

      于是就解决了这个问题。

      所以这个通过率是怎么回事……是不是都被某毒瘤出题人的 B 题拦住了?

    代码

    加了个hash表,成功把时限开到了标程4倍。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=500005,mod=998244353;
    int Pow(int x,int y){
        int ans=1;
        for (;y;y>>=1,x=1LL*x*x%mod)
            if (y&1)
                ans=1LL*ans*x%mod;
        return ans;
    }
    int read(){
        int x=0;
        char ch=getchar();
        while (!isdigit(ch))
            ch=getchar();
        while (isdigit(ch))
            x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x;
    }
    int n,Fac[N],Inv[N],Ha[N],tax[N],hs=0,tot=0;
    struct Building{
        int a,c;
    }x[N];
    struct hash_map{
        static const int Ti=233,mod=1<<19;
        int cnt,k[mod+1],v[mod+1],nxt[mod+1],fst[mod+1];
        int Hash(int x){
            unsigned t=x;
            int v=(t<<3^t)&(mod-1);
            return v==0?mod:v;   
        }
        void clear(){
            cnt=0;
            memset(fst,0,sizeof fst);
        }
        void update(int x,int a){
            int y=Hash(x);
            for (int p=fst[y];p;p=nxt[p])
                if (k[p]==x){
                    v[p]=a;
                    return;
                }
            k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt,v[cnt]=a;
            return;
        }
        int find(int x){
            int y=Hash(x);
            for (int p=fst[y];p;p=nxt[p])
                if (k[p]==x)
                    return v[p];
            return 0;
        }
        int &operator [] (int x){
            int y=Hash(x);
            for (int p=fst[y];p;p=nxt[p])
                if (k[p]==x)
                    return v[p];
            k[++cnt]=x,nxt[cnt]=fst[y],fst[y]=cnt;
            return v[cnt]=0;
        }
    }Map;
    vector <int> v[N];
    int main(){
    //freopen("city9.in","r",stdin);
    //freopen("city9.out","w",stdout);
    //int st=clock();
        n=read();
        for (int i=Fac[0]=1;i<=n;i++){
            Fac[i]=1LL*Fac[i-1]*i%mod;
            v[i].clear();
        }
        Inv[n]=Pow(Fac[n],mod-2);
        for (int i=n;i>=1;i--)
            Inv[i-1]=1LL*Inv[i]*i%mod;
        for (int i=1;i<=n;i++)
            Inv[i]=1LL*Inv[i]*Fac[i-1]%mod;
        Map.clear();
        for (int i=1;i<=n;i++){
            x[i].a=read(),x[i].c=read();
            if (!Map[x[i].c])
                Map[x[i].c]=++tot;
            x[i].c=Map[x[i].c];
            Ha[++hs]=x[i].a;
        }
        sort(Ha+1,Ha+hs+1);
        hs=unique(Ha+1,Ha+hs+1)-Ha-1;
        memset(tax,0,sizeof tax);
        for (int i=1;i<=n;i++){
            x[i].a=lower_bound(Ha+1,Ha+hs+1,x[i].a)-Ha;
            tax[x[i].a]++;
            v[x[i].c].push_back(x[i].a);
        }
        for (int i=hs;i>=1;i--)
            tax[i]+=tax[i+1];
        int ans=0;
        for (int i=1;i<=tot;i++){
            vector <int> &a=v[i];
            sort(a.begin(),a.end());
            a.push_back(a.back()+1);
            int h=a[0],cnt=1,now=1;
            for (int j=1;j<a.size();j++){
                if (a[j]!=a[j-1]){
                    int t=tax[a[j-1]];
                    now=1LL*now*(mod+1-1LL*cnt*Inv[t]%mod)%mod;
                    cnt=0;
                }
                cnt++;
            }
            ans=(ans+mod+1-now)%mod;
        }
        ans=1LL*ans*Fac[n]%mod;
        printf("%d",ans);
    //cerr << "user time = " << clock()-st << endl;
        return 0;
    }
    

      

    数据生成器

    里面有参数自行调整。

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned uint;
    const int N=1000005;
    int n=500000,m=1000,A[N],C[N];
    int Rand(int n){
    	uint a=rand(),b=rand();
    	return (a<<16|b)%n;
    }
    int main(){
    	srand(time(NULL));
    	freopen("city9.in","w",stdout);
    	printf("%d
    ",n);
    	A[0]=C[0]=1;
    	for (int i=1;i<=n;i++){
    		int a,c;
    		int p1=Rand(20),p2=Rand(20);
    		if (p1)
    			a=Rand(m)+1;
    		else
    			a=A[Rand(i)];
    		if (p2)
    			c=Rand(m)+1;
    		else
    			c=C[Rand(i)];
    		printf("%d %d
    ",A[i]=a,C[i]=c);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/NowCoder-Wannafly26D.html
Copyright © 2011-2022 走看看