2021 牛客多校 第四场 选做

Link(需报名看题)

比赛小记

我过了几个签到,牛逼题(B、C、E)都是学长过的(orz学长)

J 莫名其妙(因为精度?)wa了好几发,这把只贡献罚时了属于是

B. Sample Game

题意

\(n\) 个数和一个空数列,每次向数列中随机添加一个数,添加数 \(i\) 的概率为 \(p_i\),当数列不是单调不降时停止操作。求数列长度的平方的期望。

\(2\le n\le 100\)

Solution

orz学长

类比 bzoj osu! 的做法,我们可以考虑把 \(x^2\) 拆开,令 \(f_{i,0/1/2}\) 分别表示到 \(i\) 的概率;到 \(i\) 的长度的期望和到 \(i\)​ 的长度平方的期望。可得:

\[\begin{align*} f_{i,0}&= p_i\sum_{j=0}^{i}f_{j,0}\\ f_{i,1}&=p_i\sum_{j=0}^{i}(f_{j,1}+f_{j,0})\\ f_{j,2}&=p_i\sum_{j=0}^{i}(f_{j,2}+2f_{j,1}+f_{j,0}) \end{align*} \]

移项一下即可得到递推式,统计答案相当于再加上一个 \(\lt i\) 的点,直接做即可。

code

(by 学长)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
 
#define Rep(i, n) for (int i = 1; i <= n; i ++)
#define Rep0(i, n) for (int i = 0; i <= n; i ++)
#define RepG(i, x) for (int i = head[x]; i; i = edge[i].to)
#define v edge[i].to
#define mp(a, b) make_pair(a, b)
#define fi first
#define se second
 
typedef double D;
typedef long long LL;
 
const int mod = 998244353;
 
LL p[110], f[110][3];
LL qpow(LL a, LL b)
{
    LL ret = 1, base = a;
    while (b) {
        if (b & 1) ret = ret * base % mod;
        base = base * base % mod, b >>= 1;
    }
    return ret;
}
 
int main()
{
    int n, sum = 0;
    scanf("%d", &n);
    Rep(i, n) { scanf("%d", &p[i]); sum += p[i];}
    sum = qpow(sum, mod - 2);
    Rep(i, n) p[i] = p[i] * sum % mod;
     
    LL s0 = 1, s1 = 0, s2 = 0;
    f[0][0] = 1;
    Rep(i, n) {
        LL tmp = qpow(1 - p[i] + mod, mod - 2);
        f[i][0] = s0 * p[i] % mod * tmp % mod;
        s0 = (s0 + f[i][0]) % mod;
        f[i][1] = (s0 + s1) * p[i] % mod * tmp % mod;
        s1 = (s1 + f[i][1]) % mod;
        f[i][2] = (s2 + s0 + s1 * 2) * p[i] % mod * tmp % mod;
        s2 = (s2 + f[i][2]) % mod;
    }
    LL sp = 0, ans = 0;
    Rep(i, n) {
        LL tmp = sp * (f[i][2] + f[i][0] + f[i][1] * 2) % mod;
        ans = (ans + tmp) % mod, sp = (sp + p[i]) % mod;
    }
     
    printf("%lld\n", ans);
     
    return 0;
}

E. Tree Xor

Solution

显然题意可以转化成求满足 \(x_i~\mathrm{xor}~w'_i\in[l_i,r_i]\)​ 的 \(x\)​ 的个数(这里 \(w_i\)​​ 为当前点到根的 \(w_i\) 异或和)。

考虑 \([l_i,r_i]\)​​ 一定能拆分成 \(\text{trie}\)​​ 树上 \(\log\) 段区间,而 \(\text{xor}\)​ 操作相当于交换 \(\text{trie}\) 树上若干子树,不会影响区间数量。我们对于异或可以在根节点打上标记,然后将 \([l_i,r_i]\) 直接插入 \(\text{trie}\) 树即可。

code

#include<bits/stdc++.h>
using namespace std;
inline int gi()
{
    char c=getchar(); int x=0;
    for(;c<'0'||c>'9';c=getchar());
    for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
    return x;
}
const int N=3e5+5;
int n,l[N],r[N],w[N],x[N],ch[N*30][2],tag[N*30],add[N*30],tot=1,ans;
vector<pair<int,int>> e[N];
void dfs(int u, int fa)
{
    for(auto x:e[u]) if(x.first!=fa)
    {
        w[x.first]=w[u]^x.second;
        dfs(x.first,u);
    }
}
void pushdown(int u, int i, bool f)
{
    if(!ch[u][0]&&f) ch[u][0]=++tot;
    if(!ch[u][1]&&f) ch[u][1]=++tot;
    if(!tag[u]) return ;
    if(tag[u]&(1<<i)) swap(ch[u][0],ch[u][1]);
    tag[ch[u][0]]^=tag[u],tag[ch[u][1]]^=tag[u];
    tag[u]=0;
}
void trie_ins(int l, int r, int u=1, int x=0, int i=29)
{
    if(i<0)
    {
        ++add[u];
        return ;
    }
    pushdown(u,i,1);
    if(l<=x&&x+(1<<i+1)-1<=r)
    {
       ++add[u];
       return ;
    }
    if(x+(1<<i)-1>=l) trie_ins(l,r,ch[u][0],x,i-1);
    if(x+(1<<i)<=r) trie_ins(l,r,ch[u][1],x|(1<<i),i-1);
}
void trie_dfs(int u=1, int sum=0, int i=29)
{
    if(!u) return ;
    pushdown(u,i,0);
    sum+=add[u];
    if(sum==n)
    {
        ans+=(1<<i+1);
        return ;
    }
    if(i<0) return ;
    trie_dfs(ch[u][0],sum,i-1);
    trie_dfs(ch[u][1],sum,i-1);
}
int main()
{
    n=gi();
    for(int i=1;i<=n;++i) l[i]=gi(),r[i]=gi();
    for(int i=1;i<n;++i)
    {
        int u=gi(),v=gi(),w=gi();
        e[u].push_back(make_pair(v,w)),e[v].push_back(make_pair(u,w));
    }
    dfs(1,0);
    for(int i=1;i<=n;++i)
    {
        tag[1]^=w[i];
        trie_ins(l[i],r[i]);
        tag[1]^=w[i];
    }
    trie_dfs();
    printf("%d\n",ans);
}

G. Product

题意

给定 \(n,k,D\),定义数列 \(\{a_n\}\) 的价值为

\[\frac{D!}{\prod_{i=1}^n(a_i+k)!} \]

求所有满足以下条件的数列 \(\{a_n\}\) 的价值之和:

  1. \(\forall i\in[1,n],a_i\ge 0\)
  2. \(\sum_{i=1}^n a_i=D\)

\(998244353\)​ 取模。

\(1\le n\le 50\)\(0\le k\le 50\)\(0\le D\le 10^8\)

Solution

考虑 \(k=0\)​​ 下该式的组合意义,考虑有一个长度为 \(D\)​​ 的序列,而 \(a_i\)​​ 为 \(i\)​​ 出现的次数,那么 \(\sum_{a_i\ge 0,\sum a_i=D}\frac{D!}{\prod_{i=1}^n a_i!}\)​​ 即为值域为 \([1,n]\)​​ 的长度为 \(D\)​​​ 的数列个数(缩排),即为 \(n^D\)​。

我们直接令 \(a_i\) 加上 \(k\) ,题意转化为求 \(\sum_{a_i\ge k,\sum a_i=D+nk}\frac{D!}{\prod_{i=1}^n a_i!}\)。若无 \(a_i\ge k\) 的限制,答案即为 \(\frac{D!}{(D+nk)!}n^{D+nk}\)。对于限制,我们考虑容斥:令 \(x\)\(a_i\lt k\) ,这些 \(\frac{1}{a_i!}\) 的贡献可以用 \(O(n^2k^2)\) 的背包求出;剩余 \(n-x\) 个数的贡献即为 \(\frac{D!}{(D+nk-s)!}n^{D+nk-s}\)\(s\) 为 打破限制的 \(x\) 个数之和),乘起来再乘上容斥系数即可。

code

#include<bits/stdc++.h>
using namespace std;
const int N=55,M=N*N,Mod=998244353;
int n,k,d,f[N][M],fac[M],inv[M],ans;
#define mul(x,y) (1ll*(x)*(y)%Mod)
inline int add(int x, int y)
{   return (x+y>=Mod?x+y-Mod:x+y);
}
inline int sub(int x, int y)
{   return (x-y<0?x-y+Mod:x-y);
}
inline void upd(int& x, int y)
{   x=(x+y>=Mod?x+y-Mod:x+y);
}
inline int po(int x, int y)
{
    int r=1;
    while(y)
    {
        if(y&1) r=mul(r,x);
        x=mul(x,x), y>>=1;
    }
    return r;
}
inline int C(int x, int y)
{
    return mul(fac[x],mul(inv[y],inv[x-y]));
}
int calcd(int delta)
{
    int r=1;
    for(int i=d+1;i<=d+delta;++i) r=mul(r,i);
    return po(r,Mod-2);
}
int main()
{
    scanf("%d%d%d",&n,&k,&d);
    fac[0]=inv[0]=1;
    const int m=max(n,n*(k-1));
    for(int i=1;i<=m;++i) fac[i]=mul(fac[i-1],i);
    inv[m]=po(fac[m],Mod-2);
    for(int i=m-1;i>0;--i) inv[i]=mul(inv[i+1],i+1);
    f[0][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=0;j<=(i-1)*(k-1);++j)
            for(int l=0;l<k;++l)
                    upd(f[i][j+l],mul(f[i-1][j],inv[l]));
    for(int i=0;i<=n;++i)
    {
        for(int j=0;j<=i*(k-1);++j)
        {
            const int delta=n*k-j;
            int tmp=mul(f[i][j],mul(po(n-i,d+delta),calcd(delta)));
            if(i&1) ans=sub(ans,mul(tmp,C(n,i)));
            else ans=add(ans,mul(tmp,C(n,i)));
        }
    }
    printf("%d\n",ans);
}
posted @ 2021-07-26 21:50  x_faraway_x  阅读(47)  评论(0)    收藏  举报