内存限制了12MB.
所以输入是题目给的随机数。
数据大小是5*10^7,可以将其分成781250份,每份一个ULL表示状压,最后树状数组做。
学到了__builtin_popcountll(),快速得到一个二进制数中有几个1.
代码:
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
const double PI = acos(-1.0);
const double eps = 1e-10;
int dcmp(double x) { if(fabs(x) < eps) return 0; else return x<0?-1:1; }
const int INF = 0x3f3f3f3f;
const int N = 781250+5;
int b[N], sz;
ull a[N];
struct RandGen {
int x, y, z;
int nextInt() {
int t = x ^ (x << 11);
x = y;
y = z;
z ^= (z >> 19) ^ t ^ (t >> 8);
return z;
}
int random(int x) { return nextInt() % x; }
};
void init(int n) {
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
sz = (n+63)/64;
}
int lowbit(int x) { return x&-x; }
void add(int x, int d) {
while(x <= sz) {
b[x] += d;
x += lowbit(x);
}
}
void flipPosition(int poz) {
int x = (poz>>6)+1;
ull mask = 1llu<<(poz&63);
if(mask & a[x]) {
a[x] ^= mask;
add(x, -1);
}
else {
a[x] ^= mask;
add(x, 1);
}
}
int sum(int poz) {
if(poz < 0) return 0;
int ret = 0, x = (poz>>6)+1;
ull mask = 1llu<<(poz&63);
if(mask > 0) mask += mask-1;
ret += __builtin_popcountll(a[x]&mask);
x--;
while(x > 0) {
ret += b[x];
x -= lowbit(x);
}
return ret;
}
int getCount(int st, int fn) { return sum(fn)-sum(st-1); }
int main() {
int n, m;
RandGen rng;
cin >> n >> m >> rng.x >> rng.y >> rng.z;
init(n);
long long hashSol = 0;
for (long long i = 0; i < m; i++) {
if (rng.random(2) == 0) {
const int poz = rng.random(n);
flipPosition(poz);
}
else {
int st = rng.random(n), fn = rng.random(n);
if (st > fn) swap(st, fn);
hashSol ^= i * getCount(st, fn);
}
}
cout << hashSol << "\n";
}