2024牛客暑期多校训练营1 B题

题目说明:

题面:给定n,m,q,构造一个长度为n的数组,其中数组中的每个元素大小均小于,若该数组的某两个不同子序列中,所有元素按位与(AND)之后的结果为1,则该数组合法。求有多少种合法数组

例如n=3,m=3,q=100000

[1,0,3]是一个合法数组,因为子序列[1]的AND结果为1

[5,3,0]是一个合法数组,因为子序列[5,3]的AND结果为1

思路:

该题目与A题唯一的区别为,至少一个子序列变成了至少两个不同的子序列。A题中求解出的是包含至少一个子序列的合法数组的方案数。

   实际上也就是将A题中的方案数中,排除掉仅有一个子序列相与为1的情况。

例如A题中

    若n取3,m取3 

1. [3,5,0]是一个仅有一个子序列[3,5]相与为1的,不会有第二个子序列

2. [1,3,5]是不仅一个子序列相与为1的,它有[1],[1,3],[1,3,5],[3,5]

我们的目的是找出第一种情况(仅有一个子序列相与为1)的方案数,然后用A题求出的结果减去该方案数

如何找出仅有一个子序列相与为1的合法数组?

1.若有一个子序列相与结果为1,它应当满足:子序列中,少任何一个数后相与结果都不为1,且加入其它数时,它相与结果也不能为1。

     (1)若子序列中元素个数为 i,其它n-i个数最后一位为0,那么在i个数中加入其它(n-i)数相与结果不会为1。

     (2)什么情况下,少掉一个数会使得相与结果不为1呢?

       查看如下二进制表,当某一位仅有1个0,且该0被第i个数占有,删除第i个数时,该位将变成1,也就不符合相与为1的结果了。

该位仅有一个0至少一个0全1
第一个数1..1
....1..1
第i个数0..1

       我们称上述仅有1个位置为0的情况成为“独特位”

2.那么子序列中的i个元素,每人至少有1个独特位,设dp[i][j]表示共i个元素,有j个独特位,且每人都有一个的方案数。(状态转移方程求解在下方)

从n个位置中,挑出i个元素,方案数为:

C_{n}^{i}

从m-1个位置中,挑出j个独特位的方案数为:

C_{m-1}^{j}

剩下m-1-j个非独特位,需满足至少2个0,也就是不能全1(1个),也不能只有1个0(i个),得到的方案数为:

(2^i-i-1)^{m-j-1}

剩下n-i个人,共有m-1位,二进制的排列方案数为

2^{(n-i)*(m-1)}

最终结果为:

C_{n}^{i}*(2^i-i-1)^{m-j-1}*2^{(n-i)*(m-1)}*C_{m-1}^{j}*dp[i][j]

 其中i≥2, m-1≥j≥i

因为i=1时候的方案数A题与B题一致,因此算出i≥2时候方案数的差即可

对于dp如何求值.

    我们寻找dp[i][j]与dp[i][j-1],dp[i-1][j-1]的关系。

    (1)可以发现,dp[i][j]是比dp[i][j-1]多一个独特位的,而多了一个独特位,可以将其分给i个人。

    (2)dp[i][j]比dp[i-1][j-1]多了一个人且多了一个独特位,我们不仅可以将原来的i-1个独特位分给新人,也可将多出的独特位分给新人,因此依旧会在原来的方案上乘上i,最终得到的状态方程为:

dp[i][j]=i*(dp[i][j-1],dp[i-1][j-1])

边界条件dp[0][0]=1

注:由于取模次数过多,可能导致TLE,可以参考barrett reduction的运算

这里直接贴上代码(参考快速取模算法(Barrett Reduction) - kyEEcccccc - 博客园 (cnblogs.com))

struct Mod
{
    ll m, p;
    void init(ll pp) { m = (__int128(1) << 64) / pp; p = pp; }
    friend ll operator %(const ll &x, const Mod& m)
    {
        return x - ((__int128(x) * m.m) >> 64) * m.p;
    }

} mod;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值