HDU 6057 Kanade's convolution

HDU 6057 Kanade’s convolution

$C[k]=\sum_{i \text { and } j=k} A[i\ xor\ j] * B[i \text { or } j]$

假设$p = i\ or\ j, t = i\ xor\ j$那么有$t \sub p$,其次显然 此时$i\ and\ j = p-t=p\ xor\ t$

$C[k] = \sum_{p\ xor\ t=k} \alpha(p,t)A[t]B[p]$

$\alpha(p,t)$就是对于一对$p , t$有多少的$i,j$与之对应。

对于每一位来考虑,如果这位$p = 1 , t = 0$那么显然$i , j$在这一位都是$1$

如果$p = 1 , t = 1$那么这一位 可以$i = 1 , j = 0$或者$i = 0 , j = 1$

否则如果$p = 0 , t = 0$这一位 只能都是$0$

所以实际上, 2 的$t$的 1 的个数次方就是$\alpha(p,t)$

所以式子就是$\displaystyle\sum_{p\ xor\ t=k,t\sub p} 2^{cnt(t)}A[t]B[p]$

$p\ xor\ t = k , t \sub p $也就等价于$|p| - |t| = |k| , p\ xor\ t = k$这个可以枚举$|p|,|t|$来做,和子集卷积一样,复杂度$n^22^n$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
#define MAXN ( 1 << 20 ) + 12
#define P 998244353
//#define int long long
typedef long long ll;
int n , inv2;
int A[MAXN] , B[MAXN] , I[MAXN];
int Pow( int a , int x ) {
int res = a , ans = 1;
while( x ) {
if( x & 1 ) ans = 1ll * ans * res % P;
res = 1ll * res * res % P , x >>= 1;
}
return ans;
}
namespace fwt {

inline void FWT1(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
a[j + (mid >> 1)] += a[j] , a[j + (mid >> 1)] %= P;
}

inline void IFWT1(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
a[j + (mid >> 1)] -= a[j] , a[j + (mid >> 1)] += P , a[j + (mid >> 1)] %= P;
}

inline void FWT2(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
a[j] += a[j + (mid >> 1)];
}

inline void IFWT2(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
a[j] -= a[j + (mid >> 1)];
}

inline void FWT3(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++) {
ll x = a[j], y = a[j + (mid >> 1)];
a[j] = ( x + y ) % P, a[j + (mid >> 1)] = ( x - y + P ) % P ;
}
}

inline void IFWT3(int a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++) {
ll x = a[j], y = a[j + (mid >> 1)];
a[j] = ( 1ll * (x + y) % P * inv2 ) % P, a[j + (mid >> 1)] = ( 1ll * (x - y + P) % P * inv2 ) % P;
}
}
}

int a[20][MAXN] , b[20][MAXN] , ans[20][MAXN] , res[MAXN];
signed main() {
cin >> n;
inv2 = Pow( 2 , P - 2 );
int len = ( 1 << n );
for( int i = 0 ; i < len ; ++ i ) scanf("%d",&A[i]) , a[__builtin_popcount( i )][i] = 1ll * A[i] * ( 1 << ( __builtin_popcount( i ) ) ) % P;
for( int i = 0 ; i < len ; ++ i ) scanf("%d",&B[i]) , b[__builtin_popcount( i )][i] = B[i];
for( int i = 0 ; i <= n ; ++ i ) fwt::FWT3( a[i] , len ) , fwt::FWT3( b[i] , len );
for( int i = 0 ; i <= n ; ++ i ) {
for( int j = 0 ; j <= i ; ++ j ) {
for( int k = 0 ; k < len ; ++ k )
( ans[j][k] += 1ll * a[i - j][k] * b[i][k] % P ) %= P; // , cout << i - j << ' ' << k << ':' << a[i - j][k] << endl;;
}
}
for( int i = 0 ; i <= n ; ++ i ) fwt::IFWT3( ans[i] , len );
for( int i = 0 ; i < len ; ++ i ) res[i] = ans[__builtin_popcount( i )][i];
int c = 1 , ret = 0;
for( int i = 0 ; i < len ; ++ i )
ret = ( ret + 1ll * res[i] * c % P ) % P , c = 1ll * c * 1526 % P; // , cout << res[i] << endl;
cout << ret << endl;
}
文章作者: yijan
文章链接: https://yijan.co/old71/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog