题解
JZM 终于打完国赛回来了!为了放松一下,JZM 等人瞒着同学们去爬山。
JZM 在山脚买了份地图,地图共有 N 行,M 列,N×M 个格子,每个格子里的数(记为 a i , j a_{i,j} ai,j)表示这座山的高度, 1 ≤ a i , j ≤ K 1\leq a_{i,j}\leq K 1≤ai,j≤K 。JZM 发现在每行开头和每列开头都有数字,具体地,每行开头的数字形成序列 A,每列开头的数字形成序列 B,A、B 满足
A i = a i , 1 & a i , 2 & a i , 3 & ⋯ & a i , M ( 1 ≤ i ≤ N ) B j = a 1 , j ∣ a 2 , j ∣ a 3 , j ∣ ⋯ ∣ a N , j ( 1 ≤ i ≤ M ) A_i=a_{i,1}\;\&\;a_{i,2}\;\&\;a_{i,3}\;\&\cdots\;\&\;a_{i,M}(1\leq i\leq N)\\ B_j=a_{1,j}\;|\;a_{2,j}\;|\;a_{3,j}\;|\cdots\;|\;a_{N,j}(1\leq i\leq M) Ai=ai,1&ai,2&ai,3&⋯&ai,M(1≤i≤N)Bj=a1,j∣a2,j∣a3,j∣⋯∣aN,j(1≤i≤M)
JZM 突然好奇想问你一个问题:给定 N , M , K N,M,K N,M,K ,共有多少种 A , B A,B A,B 序列的情况存在?两种状况不同当且仅当 A A A 序列中某个数不同或 B B B 序列中某个数不同。答案对 998244353 取模。
2 ≤ N , M ≤ 1 0 18 , 1 ≤ K ≤ 5 × 1 0 5 2 ≤ N, M ≤ 10^{18}, 1 ≤ K ≤ 5 × 10^5 2≤N,M≤1018,1≤K≤5×105
Sample Input #1
2 2 2
Sample Output #1
15
Sample Input #2
3 3 5
Sample Output #2
615
Sample Input #3
7 10 20
Sample Output #3
329564051
题解
不难发现,由于每个 A i A_i Ai 限制了一整行的 a i , j a_{i,j} ai,j 二进制中哪些 1 必须有,而 B j B_j Bj 又是对一整列求或,其中每一行的数都会有,因此 ( A 1 ∣ A 2 ∣ A 3 ∣ . . . ∣ A N ) ⊆ ( B 1 & B 2 & B 3 & . . . & B M ) (A_1|A_2|A_3|...|A_N)\sube(B_1\,\&\,B_2\,\&\,B_3\,\&...\&\,B_M) (A1∣A2∣A3∣...∣AN)⊆(B1&B2&B3&...&BM)
这里的 “ ⊆ \sube ⊆” 即二进制下是否为子集( x ⊆ y ⇔ x & y = x x\sube y\;\Leftrightarrow\; x\;\&\;y=x x⊆y⇔x&y=x),满足这个条件后呢?现在我们要证明这是一种方案 A , B A,B A,B 合法的充要条件。
如果满足这个条件,我们尝试把矩阵构造出来,先把第 i i i 行都赋值为 A i A_i Ai 的值,然后去满足 B B B ,我们只需要把每一列选一个数赋为 B j B_j Bj 就行了,那么,只要不是只有一行的极端情况,那么就还有数字可以满足 A A A,但是题目已经给出范围: 2 ≤ N , M 2\leq N,M 2≤N,M ,因此一定有解。
证明了充要条件后,我么就可以放心计数了。枚举 ( A 1 ∣ A 2 ∣ A 3 ∣ . . . ∣ A N ) (A_1|A_2|A_3|...|A_N) (A1∣A2∣A3∣...∣AN) ,加上此时 A A A 的方案数 × B B B 的方案数,这个只需要快速沃尔什变换就行了,当然也没必要 O ( K log 2 k ) O(K\log^2k) O(Klog2k) 去解决,我们只需要卷一次,然后每个单独元素快速幂后卷回来就行。复杂度 O ( K log K ) O(K\log K) O(KlogK) 。
CODE
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 500005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {
if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {
x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
void MD(int &x) {
if(x>=MOD)x-=MOD;}
int qkpow(int a,LL b) {
b %= (MOD-1);int res = 1;
while(b > 0) {
if(b & 1) res = res *1ll* a % MOD;
a = a *1ll* a % MOD; b >>= 1;
}return res;
}
int A[MAXN<<2],B[MAXN<<2];
void DWTOR(int *s,int n) {
for(int k = 2;k <= n;k <<= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j;i < j+(k>>1);i ++) {
MD(s[i+(k>>1)] += s[i]);
}
}
}return ;
}
void IDWTOR(int *s,int n) {
for(int k = n;k > 1;k >>= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j;i < j+(k>>1);i ++) {
MD(s[i+(k>>1)] += MOD-s[i]);
}
}
}return ;
}
void DWTAND(int *s,int n) {
for(int k = 2;k <= n;k <<= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j;i < j+(k>>1);i ++) {
MD(s[i] += s[i+(k>>1)]);
}
}
}return ;
}
void IDWTAND(int *s,int n) {
for(int k = n;k > 1;k >>= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j;i < j+(k>>1);i ++) {
MD(s[i] += MOD-s[i+(k>>1)]);
}
}
}return ;
}
int main() {
freopen("pair.in","r",stdin);
freopen("pair.out","w",stdout);
LL N = read(),M = read();m = read();
int le = 1;while(le <= m) le <<= 1;
for(int i = 0;i <= m;i ++) {
A[i] = B[i] = 1;
}
DWTOR(A,le);
for(int i = 0;i < le;i ++) A[i] = qkpow(A[i],N);
IDWTOR(A,le);
DWTAND(B,le);
for(int i = 0;i < le;i ++) B[i] = qkpow(B[i],M);
int ans = 0;
for(int i = 0;i <= m;i ++) {
MD(ans += A[i] *1ll* B[i] % MOD);
}
printf("%d\n",ans);
return 0;
}