[ICPC2020上海C] Sum of Log
Description
给定 (x,y le 10^9) 求 (sum_{i=0}^x sum_{j=[i=0]}^y [i & j=0][log_2(i+j)+1])。
Solution
显然带 (log) 的那一项相当于是 (i,j) 的最大值的最高位,因此我们暴力枚举最高位是第几位,由谁贡献,后面的部分简单数位 dp 即可
考场上的代码,写得比较丑
(第一次正儿八经在考场上写出数位dp,魔咒算是破了)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 65;
const int mod = 1e+9+7;
int a[N], b[N], f[N][2][2];
int solve(int pos, int limi, int limj)
{
if (pos == 0)
{
return 1;
}
if (~f[pos][limi][limj])
{
return f[pos][limi][limj];
}
int res = 0;
if (limi == 0 || a[pos] == 1)
{
res += solve(pos - 1, limi, limj && b[pos] == 0);
}
if (limj == 0 || b[pos] == 1)
{
res += solve(pos - 1, limi && a[pos] == 0, limj);
}
res += solve(pos - 1, limi && a[pos] == 0, limj && b[pos] == 0);
res %= mod;
if (f[pos][limi][limj])
{
f[pos][limi][limj] = res;
}
return res;
}
int solve(int x, int y)
{
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for (int i = 0; i < N; i++)
{
f[i][0][1] = f[i][1][0] = f[i][1][1] = -1;
}
int n = 0, m = 0;
while (x)
{
a[++n] = x % 2;
x /= 2;
}
while (y)
{
b[++m] = y % 2;
y /= 2;
}
int presumi = 0, presumj = 0;
for (int i = m; i > n; i--)
presumj += b[i];
int ans = 0;
for (int high = n; high >= 1; high--)
{
presumi += a[high];
presumj += b[high];
if (presumi >= 1)
{
// cout << "[";
ans += solve(high - 1, presumi == 1 && a[high] == 1, presumj == 0) * high;
ans %= mod;
// cout << "]";
}
}
return ans;
}
void solve()
{
int x, y;
scanf("%lld%lld", &x, &y);
int ans = 0;
ans += solve(x, y);
ans += solve(y, x);
printf("%lld
", ans % mod);
}
signed main()
{
ios::sync_with_stdio(false);
memset(f, -1, sizeof f);
int t;
scanf("%lld", &t);
while (t--)
{
solve();
}
}