题目链接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;
}