描述
题解
虽然是四级题,但是真不会,找了题解,甚是不错。
以下题解来自abclzr的博客:
对区间分治,统计[l, r]
中经过mid的区间的答案。
我的做法是从mid向右扫到r,统计出所有[mid, i], mid ≤ i ≤ r
的and和or值。
然后发现这些and
和or
值有很多相同的,把相同的压在一起并记录sum,再从mid - 1
扫到l
并暴力从mid
向右统计答案。
事实上因为[mid, i], mid ≤ i ≤ r
是连续的,所以压完后的个数是O(2loga)
(a为10^9)。这样时间复杂度是O(nlognloga)
。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int cinDiy()
{
int k = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) ;
for (; c >= '0' && c <= '9'; c = getchar())
{
k = k * 10 + c - 48;
}
return k;
}
const ll MOD = 1e9 + 7;
const int MAXN = 1e5 + 10;
int a[MAXN];
int AND[MAXN];
int OR[MAXN];
int sum[MAXN], resA, resO;
ll ans = 0;
void solve(int l, int r)
{
if (l == r)
{
return ;
}
int mid = (l + r + 1) >> 1;
ll pos = mid;
AND[pos] = OR[pos] = a[mid];
sum[pos] = 1;
for (int i = mid + 1; i <= r; ++i)
{
if (((AND[pos] & a[i]) != AND[pos]) || ((OR[pos] | a[i]) != OR[pos]))
{
++pos;
AND[pos] = AND[pos - 1] & a[i];
OR[pos] = OR[pos - 1] | a[i];
sum[pos] = 1;
}
else
{
++sum[pos];
}
}
resA = resO = a[mid - 1];
for (int i = mid - 1; i >= l; --i)
{
resA &= a[i];
resO |= a[i];
for (int j = mid; j <= pos; ++j)
{
ans = (ans + (ll)(resA & AND[j]) * (ll)(resO | OR[j]) % MOD * (ll)(sum[j]) % MOD) % MOD;
}
}
solve(l, mid - 1);
solve(mid, r);
}
int main()
{
int n;
n = cinDiy();
for (int i = 1; i <= n; ++i)
{
a[i] = cinDiy();
ans = (ans + 1ll * a[i] * a[i]) % MOD; // 序列[i, i]
}
solve(1, n);
printf("%d\n", (int)ans);
return 0;
}