2024牛客暑期多校训练营1 A Bit Common

题目链接A-A Bit Common_2024牛客暑期多校训练营1 (nowcoder.com)

题目描述 

Given two integers nnn and mmm, among all the sequences containing nnn non-negative integers less than 2^m, you need to count the number of such sequences A that there exists a non-empty subsequence of Ain which the bitwise AND of the integers is 1.

Note that a non-empty subsequence of a sequence A is a non-empty sequence that can be obtained by deleting zero or more elements from A and arranging the remaining elements in their original order.

Since the answer may be very large, output it modulo a positive integer q.

The bitwise AND of non-negative integers A and B, A AND B is defined as follows:

  • When A AND B is written in base two, the digit in the 2^d's place (d≥0) is 1 if those of A and B are both 1, and 0 otherwise.

For example, we have 4 AND 6 = 4 (in base two: 100 AND 110 = 100).

Generally, the bitwise AND of k non-negative integers p1,p2,…,pk​ is defined as
(…((p1 AND p2) AND p3) AND … AND pk)
and we can prove that this value does not depend on the order of p1,p2,…,pk.

题目大意

求有多少长为 n 的元素是 [0, 2 m) 的整数序列

满足存在一个非空子序列的 AND 和是 1

答案对输入的正整数 q 取模

1 ≤ n, m ≤ 5000, 1 ≤ q ≤ 109

输入描述:


The only line contains three integers n (1≤n≤5 000), m (1≤m≤5 000) and qqq (1≤q≤10^9).

输出描述:


Output a line containing an integer, denoting the answer.

示例1

输入

2 3 998244353

输出

17

示例2

输入

5000 5000 998244353

输出

2274146

题目大意

求有多少长为 n 的元素是 [0, 2 m) 的整数序列 满

足存在一个非空子序列的 AND 和是 1

答案对输入的正整数 q 取模

1 ≤ n, m ≤ 5000, 1 ≤ q ≤ 10^9

解题思路

二进制最低位为 0 的数一定不在 AND 和是 1 的子序列里,这些数除了 最低位都可以任选

对于二进制最低位为 1 的数,如果存在一个子序列的 AND 和是 1,那 么包含这个子序列的子序列的 AND 和也是 1

只要所有二进制最低位为 1 的数 AND 和是 1 就能满足条件

假设n为4,m为4,任意一种排列情况可能如上图。要使得这组排列有非空子排列的AND和为1,有以下几个条件

        这个排列里必定有至少一个以上的数字末位为1。假设为k个,这里有Cnk​种情况

        对于末位为1的数字,每一位都至少有一个0。这里有2k−1(所有的可能为2k,减去一种该k个都是1的情况),总共m−1位需要选择是0还是1,一共(2^k−1)^(m−1)

        对于末位为00的数字,每一位是0还是1随便,这里有2^(n−k),总共总共m−1位需要选择是0还是1,一共(2^n−k)^(m−1)=2^((n−k)(m−1))

上述所有情况需要同时满足,所有的情况数相乘,在对k从1到n求和,得到n个中k个末位为1,含AND和为1的子集的序列个数公式:

关键点就在于求幂、求组合数,用快速幂求大指数幂,用杨辉三角递推组合数。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N = 5e3+5;
int n,m,q;
int C[N][N];
int ksm(int x,int y) {//快速幂模板
	int res=1;
	while(y) {
		if(y&1)res=res*x%q;
		x=x*x%q;
		y/=2;
	}
	return res;
}
signed main() {
	cin>>n>>m>>q;
	C[0][0]=1;
	for(int i=1; i<=5000; i++) { //组合数 
		C[i][0]=1;
		for(int j=1; j<=i; j++) {
			C[i][j]=C[i-1][j]+C[i-1][j-1];
			C[i][j]%=q;
		}
	}
	int ans=0;
	for(int i=1; i<=n; i++) {
		ans+=C[n][i]*ksm(2,(n-i)*(m-1))%q*ksm((ksm(2,i)-1)%q,m-1);
		ans%=q;
	}
	cout<<ans<<endl;
	return 0;
}
  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值