洛谷 P8569 [JRKSJ R6] 第七学区

洛谷传送门

好题,吹爆 JRKSJ!

考虑朴素的 O(nlogV) 做法。枚举第 i 位,需要计算所有极长连续的全 0 区间长度,答案为 i=0632i×(n(n+1)2len(len+1)2)

然而这样不能通过。考虑分块,每 B 个元素为一块。

  • 块内的子区间暴力枚举即可。这部分复杂度是 O(nB)
  • 算块间的贡献,考虑算出当前块第 i 位第一次出现的位置 fi 和最后一次出现的位置 gi。再维护一个 lsti 表示前面的块第 i 位最后一次出现的位置。考虑计算块内的前缀或序列 si,那么 sisi1 就是 ai 在块中第一次出现的位。这部分的时间复杂度为 O(2nlogVB)
  • 算出来 figi,考虑计算块间的贡献。枚举第 i 位,沿用暴力方法,右端点在当前块的全 0 区间数量为 (fil)×(llsti1)。若当前块的所有元素的第 i 位都是 0,数量就是 (rl+1)×(llsti1)。每次用 gi 更新 lsti 即可。这部分的时间复杂度为 O(nlogVB)

总时间复杂度为 O(nB+3nlogVB),实测 B=17 最优。

code
/*
p_b_p_b txdy
AThousandSuns txdy
Wu_Ren txdy
Appleblue17 txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 21], *p1 = buf, *p2 = buf;
namespace READ
{
ull Read()
{
char ch=getchar();
ull s=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s;
}
ull tp[10005];
int l,r;
ull g1,g2;
void init(int &n)
{
int i,k;
n=Read(),k=Read(),l=1;
for(i=1;i<=k;i++)
tp[i]=Read();
}
ull read()
{
if(l>r)
l=Read(),r=Read(),g1=Read(),g2=Read();
return tp[l++]*g1+g2;
}
}
const int B = 17;
int n, f[64], g[64], lst[64];
ull a[64], b[64], c[64], ans, sum;
void solve() {
READ::init(n);
for (int l = 1; l <= n; l += B) {
int r = min(l + B - 1, n), len = r - l + 1;
sum += 1ULL * len * (len + 1) / 2;
for (int i = l; i <= r; ++i) {
a[i - l + 1] = READ::read();
}
for (int i = 1; i <= len; ++i) {
ull s = 0;
for (int j = i; j <= len; ++j) {
s |= a[j];
ans += s;
}
}
mems(f, 0);
mems(g, 0);
b[0] = 0;
for (int i = 1; i <= len; ++i) {
b[i] = (b[i - 1] | a[i]);
}
for (int i = 1; i <= len; ++i) {
ull val = (b[i] ^ b[i - 1]);
while (val) {
f[__builtin_ctzll(val)] = i + l - 1;
val ^= (val & (-val));
}
}
b[len + 1] = 0;
for (int i = len; i; --i) {
b[i] = (b[i + 1] | a[i]);
}
for (int i = 1; i <= len; ++i) {
ull val = (b[i] ^ b[i + 1]);
while (val) {
g[__builtin_ctzll(val)] = i + l - 1;
val ^= (val & (-val));
}
}
for (int i = 0; i < 64; ++i) {
if (f[i]) {
c[i] += 1ULL * (f[i] - l) * (l - lst[i] - 1);
lst[i] = g[i];
} else {
c[i] += 1ULL * (r - l + 1) * (l - lst[i] - 1);
}
}
}
for (int i = 0; i < 64; ++i) {
ans += (1ULL << i) * (1ULL * n * (n + 1) / 2 - sum - c[i]);
}
printf("%llu", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
posted @   zltzlt  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示