牛客 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",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\n",A[i]=a,C[i]=c);
	}
	return 0;
}

  

posted @ 2018-10-12 22:20  zzd233  阅读(520)  评论(0编辑  收藏  举报