26.10.4qbxt集训day4
T1

直接数位dp。
点击查看代码
#include <iostream>
#include <algorithm>
using std::cin;
using std::cout;
const int N = 60;
typedef long long ll;
int a[50];
ll f[N][2][2][5][2]; // 第i位,不在/在前导,顶,j个当前的,填的是l
int main()
{
ll n;
cin >> n;
int cnt = 0;
while (n)
{
a[++cnt] = n % 2;
n /= 2;
}
std::reverse(a + 1, a + cnt + 1);
f[0][1][1][0][0] = 1;
for (int i = 1; i <= cnt; ++i)
{
if (i == 1)
f[i][0][0][0][0] = f[i][0][0][0][0] + f[i - 1][1][1][0][0];
else
f[i][0][0][0][0] = f[i][0][0][0][0] + f[i - 1][0][0][0][0];
// 不顶 1
for (int j = 0; j <= 1; ++j)
{
for (int k = 0; k <= 0; ++k)
{
for (int x = 0; x <= 2; ++x)
f[i][1][0][1][1] += f[i - 1][j][k][x][0];
}
}
f[i][1][0][2][1] += f[i - 1][1][0][1][1];
// 0
for (int j = 1; j <= 1; ++j)
{
for (int k = 0; k <= a[i]; ++k)
{
for (int x = 0; x <= 2; ++x)
f[i][1][0][1][0] += f[i - 1][j][k][x][1];
}
}
if (a[i])
f[i][1][0][2][0] += f[i - 1][1][1][1][0] + f[i - 1][1][0][1][0];
else
f[i][1][0][2][0] += f[i - 1][1][0][1][0];
// 顶
if (a[i])
{
for (int j = 0; j <= 1; ++j)
{
for (int x = 0; x <= 2; ++x)
f[i][1][1][1][1] += f[i - 1][j][1][x][0];
}
f[i][1][1][2][1] += f[i - 1][1][1][1][1];
}
else
{
for (int j = 0; j <= 1; ++j)
{
for (int x = 0; x <= 2; ++x)
f[i][1][1][1][0] += f[i - 1][j][1][x][1];
}
f[i][1][1][2][0] += f[i - 1][1][1][1][0];
}
}
ll ans = 0;
for (int j = 0; j <= 1; ++j)
{
for (int k = 0; k <= 1; ++k)
{
for (int x = 1; x <= 2; ++x)
ans += f[cnt][1][j][x][k];
}
}
cout << ans << '\n';
return 0;
}
T2

用 \(b\) 表示 \(a\),发现 \(b - n\) 一定是 \(n^2\) 的因数,再想一想就会发现只需要统计 \(n^2\) 的 \(<n\) 的因数个数即可。
点击查看代码
#include <iostream>
using std::cin;
using std::cout;
const int N = 1e6 + 10;
typedef long long ll;
int tot;
int k;
int cnt;
int p[N];
int c[N];
void dfs(int x, ll now)
{
if (x == tot + 1)
{
cnt++;
return;
}
ll mul = 1;
for (int i = 0; i <= c[x]; ++i)
{
if (now * mul < k)
dfs(x + 1, now * mul);
if (i != c[x])
mul *= p[x];
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cnt = 0;
for (int i = 1; i <= tot; ++i)
c[i] = p[i] = 0;
tot = 0;
int n;
cin >> n;
if (n == 1)
{
cout << 0 << '\n';
continue;
}
int x = n;
for (int i = 2; i * i <= x; ++i)
{
if (!(x % i))
{
p[++tot] = i;
while (!(x % i))
{
c[tot]++;
x /= i;
}
}
}
if (x > 1)
p[++tot] = x, c[tot] = 1;
for (int i = 1; i <= tot; ++i)
c[i] <<= 1;
k = n;
dfs(1, 1);
cout << cnt << '\n';
}
return 0;
}
T3
推一推式子即可。
点击查看代码
#include <iostream>
#define pc putchar
using std::cin;
using std::cout;
const int mod = 998244353;
const int N = 1e6 + 10;
int n, k;
char c[4];
int f[N];
int g[N];
void print(int n, int d, int k, int opt)
{
if (n == 0)
return;
if (opt == 0) // f
{
if (k <= f[n - 1])
print(n - 1, d, k, 0);
else if (k == f[n - 1] + 1)
{
print(n - 1, d, f[n - 1], 0);
pc(c[d]);
}
else if (k <= f[n - 1] + 1 + g[n - 1])
{
print(n - 1, d, f[n - 1], 0);
pc(c[d]);
print(n - 1, (d + 1) % 3 + 1, k - f[n - 1] - 1, 1);
}
else if (k == f[n - 1] + 1 + g[n - 1] + 1)
{
print(n - 1, d, f[n - 1], 0);
pc(c[d]);
print(n - 1, (d + 1) % 3 + 1, g[n - 1], 1);
pc(c[d % 3 + 1]);
}
else
{
print(n - 1, d, f[n - 1], 0);
pc(c[d]);
print(n - 1, (d + 1) % 3 + 1, g[n - 1], 1);
pc(c[d % 3 + 1]);
print(n - 1, d, k - f[n - 1] - 1 - g[n - 1] - 1, 0);
}
}
else // g
{
if (k <= f[n - 1])
print(n - 1, d, k, 0);
else
{
print(n - 1, d, f[n - 1], 0);
pc(c[d]);
if (k > f[n - 1] + 1)
print(n - 1, (d + 1) % 3 + 1, k - f[n - 1] - 1, 0);
}
}
}
int main()
{
c[1] = 'A', c[2] = 'B', c[3] = 'C';
cin >> n >> k;
int p = -1;
for (int i = 1; i <= n; ++i)
{
f[i] = ((f[i - 1] << 1) % mod + 2 + g[i - 1]) % mod;
g[i] = ((f[i - 1] << 1) % mod + 1) % mod;
if (f[i] >= k && p == -1)
p = i;
}
cout << f[n] << '\n';
if (p == -1)
print(n, 1, f[n], 0);
else
print(p, 1, k, 0);
return 0;
}
T4

注意到可以转换成二维数点,即可。
对于三个点对 \(i<j<k\),枚举 \(i\),找出对于 \(i\) 满足要求的最大 \(j\) 和最小 \(k\),随着 \(i\) 增大,最大的 \(j\) 一定单调不降,我们就把对于 \(j\) 合法的右射线在环上对应的区间加到树状数组里,再查询 \(i\) 的 \(k\) 端点到 \(4n\) 这个区间与区间内的区间的交的和即可。
点击查看代码
#include <iostream>
#define lowbit(x) x & (-x)
using std::cin;
using std::cout;
const int N = 1.5e6 + 10;
typedef long long ll;
struct Node
{
ll x, y;
friend Node operator-(const Node &a, const Node &b)
{
return (Node){a.x - b.x, a.y - b.y};
}
friend Node operator+(const Node &a, const Node &b)
{
return (Node){a.x + b.x, a.y + b.y};
}
friend ll operator*(const Node &a, const Node &b)
{
return a.y * b.x - a.x * b.y;
}
};
int n, m;
int mn[N << 2];
int mx[N << 2];
Node info[N << 2];
Node p[N];
Node v[N << 2];
void add(int x, Node k)
{
for (; x <= (n << 2); x += lowbit(x))
info[x] = info[x] + k;
}
void add(int l, int r, int k)
{
if (l > r)
return;
add(l - 1, (Node){k, -1ll * (l - 1) * k});
add(r, (Node){-k, 1ll * r * k});
}
Node query(int x)
{
Node ret = (Node){0, 0};
for (; x; x -= lowbit(x))
ret = ret + info[x];
return ret;
}
ll query(int l, int r)
{
if (l > r)
return 0;
Node q = query(r) - query(l - 1);
return q.y + q.x * (l - 1);
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= (n << 2); ++i)
{
if (i <= n)
v[i] = (Node){i - 1, 0};
else if (i <= (n << 1))
v[i] = (Node){n, i % (n + 1)};
else if (i <= (n << 1) + n)
v[i] = (Node){n - i % ((n << 1) + 1), n};
else
v[i] = (Node){0, n - i % ((n << 1) + n + 1)};
}
for (int i = 1; i <= m; ++i)
cin >> p[i].x >> p[i].y;
for (int i = 1; i <= (n << 2); ++i)
{
Node a = p[1], b = p[1];
for (int j = 2; j <= m; ++j)
{
if ((a - v[i]) * (p[j] - v[i]) > 0)
a = p[j];
if ((p[j] - v[i]) * (b - v[i]) > 0)
b = p[j];
}
int l = i, r = (n << 2);
int mid;
while (l <= r)
{
mid = (l + r) >> 1;
if ((a - v[i]) * (v[mid] - v[i]) >= 0)
{
mn[i] = mid;
l = mid + 1;
}
else
r = mid - 1;
}
l = i + 1, r = (n << 2);
mx[i] = -1;
while (l <= r)
{
mid = (l + r) >> 1;
if ((v[mid] - v[i]) * (b - v[i]) >= 0)
{
mx[i] = mid;
r = mid - 1;
}
else
l = mid + 1;
}
}
ll ans = 0;
for (int i = 1, j = 1; i <= (n << 2); ++i)
{
if (j > i)
add(i + 1, mn[i], -1);
for (; j <= mn[i]; ++j)
{
if (j > i)
add(j + 1, mn[j], 1);
}
if (mx[i] != -1)
ans += query(mx[i], n << 2);
}
cout << ans << '\n';
return 0;
}
讲的题:
https://files.cnblogs.com/files/blogs/832279/Dl1.zip?t=1791182204&download=true

浙公网安备 33010602011771号