bzoj

链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4589
思路:首先了解FWT解决的是$C_k$ = $A_i$ op $B_j$ (i op j = k)(op可为& | ^ 三种运算)。复杂度是O(nlogn)。其实这个东西并不需要掌握原理,只需要知道怎么用即可。本题中,相当于选出n个素数,使得他们的异或和等于0。考虑如果选两个,就是两个a序列卷积一下,三个就是两个的结果再和a序列卷积一下。我们知道,卷积通过变化后可以转化位乘法,那么多次相同的数列卷积转为幂运算,这样我们就可以快速幂解决,然后再还原回来即可。注意代码中有些小细节。

代码:

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

using namespace std;

const int mod = 1e9 + 7;
const int rev = (mod + 1) >> 1;
const int maxn = 1 << 17;
typedef long long ll;
ll a[maxn];
int n, m;
bool vis[maxn];
vector<int> prime;

void (){
for(int i = 2; i <= 50000; i++){
if(!vis[i]) prime.push_back(i);
for(int j = 0; j < prime.size() && i * prime[j] <= 50000; j++){
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}


inline ll add(ll x, ll y){
x += y;
return x >= mod ? x - mod : x;
}

inline ll sub(ll x, ll y){
x -= y;
return x < 0 ? x + mod : x;
}

ll pow_mod(ll q, ll w){
ll ret = 1;
while(w){
if(w & 1) ret = ret * q % mod;
q = q * q % mod;
w >>= 1;
}
return ret;
}

void fwt(ll a[], int n) {
for (int i = 1; i < n; i <<= 1){
for (int p = i << 1, j = 0; j < n; j += p) {
for (int k = 0; k < i; k++) {
ll x = a[j + k], y = a[j + k + i];
a[j + k] = add(x, y), a[j + k + i] = sub(x, y);
}
}
}
}

void ufwt(ll a[], int n) {
for (int i = 1; i < n; i <<= 1) {
for (int p = i << 1, j = 0; j < n; j += p) {
for (int k = 0; k < i; k++) {
ll x = a[j + k], y = a[j + k + i];
a[j + k] = 1ll * (x + y) * rev % mod, a[j + k + i] = 1ll * (x - y + mod) * rev % mod;
}
}
}
}

void solve(ll a[], int t){
fwt(a, t);
for(int i = 0; i < t; i++) a[i] = pow_mod(a[i], n);
ufwt(a, t);
cout << a[0] << 'n';
}

int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
while(cin >> n >> m) {
memset(a, 0, sizeof(a));
for(int i = 0; i < prime.size() && prime[i] <= m; i++){
a[prime[i]] = 1;
}
int t = 1;
while (t <= m) t <<= 1; //注意此处是小于等于
solve(a, t);
}
return 0;
}