zoukankan      html  css  js  c++  java
  • HDU6825:Set1——题解

    http://acm.hdu.edu.cn/showproblem.php?pid=6825

    给你一个集合$S={1..n}$。保证 $n$ 是奇数。必须执行以下操作,直到集合中只有一个元素:

    首先删除 $S$ 的最小元素,然后从 $S$ 中随机删除另一个元素。

    对于每个 $i∈[1,n]$ ,确定 $i$ 留在 $S$ 中的概率。

    emm题解u1s1很好看懂,但打的时候我反正是蒙蔽的,然后就打表做的。打表也不难,讲讲怎么打的表。

    设 $f[i][j]$ 为有 $j$ 个元素的集合里第i个元素存活概率。

    显然 $f[i][j]=((j-i)*f[i-1][j-2]+(i-2)*f[i-2][j-2])/(j-1)$ 。

    然后意识到除 $j-1$ 这块打表用不到,于是扔掉 $j-1$ 开始打表。

    然后发现惊天大秘密(

    当 $n$ 为 $1,3,5,7,9$ 时,有:

    1
    0 1 1
    0 0 2 3 3
    0 0 0 6 12 15 15
    0 0 0 0 24 60 90 105 105

    首先就是每行最后两个数相同,且都为 $(n-2)!!$ 。

    其次通过表可以发现 $f[i][j]=f[i-1][j-2]*(i-1)$ ,并且如果这个式子不断地递归下去的话,要么为 $0$ ,要么得到的式子里的 $f$ 的两维的数是一样的。

    于是对于给定的询问 $n$ 个元素当中第 $x$ 个元素存活概率,有如下算法:

    1.如果 $2*x-n-1<0$ ,则答案为 $0$ 。

    2.否则,答案为 $(x-1)!/(2*x-n-1)!*f[2*x-n][2*x-n]$ ,而 $f[2*x-n][2*x-n]=(2*x-n-2)!!$ (当然你需要为 $2*x-n=1$ 进行特判)

    最后的答案不要忘记把我们之前抛掉的除 $j-1$ 加回来,其实利用一开始的dp式子可以知道实际上答案只需要多除一个 $(n-1)!!$ 即可。

    #include<bits/stdc++.h>
    #define space putchar(' ')
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    const ll p=998244353;
    const int N=5e6+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    void write(ll x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    ll inv[N],JJ[N],J[N];
    inline ll getequ(int x){
        if(x==1)return 1;
        return JJ[x-2];
    }
    ll qpow(ll k,int n){
        ll res=1;
        while(n){
            if(n&1)res=res*k%p;
            k=k*k%p;n>>=1;
        }
        return res;
    }
    ll sol(int x,int n){
        int del=n-x;
        if(x-del-1<0)return 0;
        ll ans=J[x-1]*qpow(J[x-del-1],p-2)%p;
        return ans*getequ(x-del)%p;
    }
    void init(){
        inv[0]=inv[1]=1;J[0]=J[1]=JJ[1]=1;
        for(int i=2;i<N;i++){
            J[i]=J[i-1]*i%p;
            inv[i]=(p-p/i)*inv[p%i]%p;
        }
        for(int i=2;i<N;i+=2){
            inv[i]=inv[i]*inv[i-2]%p;
        }
        for(int i=3;i<N;i+=2){
            JJ[i]=JJ[i-2]*i%p;
        }
    }
    int main(){
        init();
        int T=read();
        while(T--){
            int n=read();
            for(int i=1;i<=n;i++){
                write(sol(i,n)*inv[n-1]%p);
                if(i!=n)space;
            }
            enter;
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    批处理禁止指定的IE的加载项
    理解一个简单的网页请求过程
    求两条直线(线段)的交点
    hdu 3635 Dragon Balls (并查集)
    uva 12452 Plants vs. Zombies HD SP (树DP)
    ural 1500 Pass Licenses (状态压缩+dfs)
    sgu 321 The Spy Network (dfs+贪心)
    poj3535 A+B (大数加法)
    zkw线段树专题
    ZOJ 2671 Cryptography 矩阵乘法+线段树
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/13434815.html
Copyright © 2011-2022 走看看