2025年08月随便做做

测试题目选集

HJJ

4C

每个 \(i\) 必须选择 \(a_i\) 或者 \(b_i\) 之中的一个数加入可重集合中。若这个集合最终有相同的数,则价值为 \(0\),否则价值为 \(\min_{x,y\in S,x\ne y}|x-y|\)。求最大的价值。

\(n\le 10^5,v\le 10^9\)

考虑二分最小距离(价值) \(d\),那么可以建图跑 2-SAT。直接线段树优化建图的时间复杂度是 \(O(n\log_2n\log_2v)\) 的。这样直接做是过不了的(大概跑 6s),但是如果把二分上界调成 \(\frac{v}{n-1}\) 就可以过(大概跑 0.7s)。但是 \(2\log\) 归根到底也不太行。于是考虑如何 \(O(n)\) 建图。所以实际上可以双栈模拟队列,这样就得到一个边数点数均为 \(O(n)\) 的图。时间复杂度 \(O(n\log_2\frac{v}{n})\)

Code
// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
#include <immintrin.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

static char buf[1000000], *p1 = buf, *p2 = buf;
#define getchar() p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 1e5;
int n, vn;
array<int, 2> a[N + 5];
pair<int, pair<int, int>> b[N * 2 + 5];
int d[N * 2 + 5], lb[N * 2 + 5], rb[N * 2 + 5];

const int Q = N * 10 + 5;
int firs[Q], nex[N * 100 + 5], to[N * 100 + 5], tot;
inline void Add(int u, int v) {
nex[++tot] = firs[u], firs[u] = tot, to[tot] = v;
}
// vector<int> to[N * 10 + 5];
int rep[N * 2 + 5], mx;

namespace sgt {
#define lson(p) ((p) << 1)
#define rson(p) ((p) << 1 | 1)
const int P = N << 3;
int lt[P], rt[P];
void Build(int p, int l, int r) {
lt[p] = l, rt[p] = r;
if (l == r) {
rep[l] = p; mx = max(mx, p);
return ;
}
int mid = (l + r) >> 1;
Add(p, lson(p)), Add(p, rson(p));
Build(lson(p), l, mid), Build(rson(p), mid + 1, r);
}
void Con(int p, int l, int r, int x) {
if (l <= lt[p] && rt[p] <= r) {
Add(x, p);
return ;
}
int mid = (lt[p] + rt[p]) >> 1;
if (l <= mid) Con(lson(p), l, r, x);
if (r > mid) Con(rson(p), l, r, x);
}
}

int idx, dfn[Q], low[Q];
bool ins[Q];
int sta[Q], top;
int scc[Q], cnt;
void Tarjan(int u) {
if (dfn[u]) return ;
dfn[u] = low[u] = ++idx;
sta[++top] = u; ins[u] = true;
for (int e = firs[u], v; e; e = nex[e]) {
v = to[e];
if (!dfn[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
} else
if (ins[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
int v;
++cnt;
do {
v = sta[top--];
scc[v] = cnt;
ins[v] = false;
} while (v != u);
}
}
inline bool doso() {
idx = cnt = top = 0;
for (int i = 1; i <= mx + n * 2; ++i) dfn[i] = low[i] = scc[i] = 0, ins[i] = false;
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 2; ++j)
Tarjan(mx + n * j + i);
if (scc[mx + i] == scc[mx + n + i])
return false;
}
return true;
}

signed main() {
STCLOCK

freopen("choose.in", "r", stdin);
freopen("choose.out", "w", stdout);

io::read(n);
for (int j = 0; j < 2; ++j)
for (int i = 1; i <= n; ++i)
io::read(a[i][j]), b[i + j * n] = make_pair(a[i][j], make_pair(i, j));
vn = n << 1;
sort(b + 1, b + vn + 1);
for (int i = 1; i <= vn; ++i)
a[b[i].second.first][b[i].second.second] = i, d[i] = b[i].first;
for (int i = 1; i <= n; ++i)
if (d[a[i][0]] == d[a[i][1]]) a[i][1] = a[i][0];

sgt::Build(1, 1, vn);
int T = 0;
int L = 1, R = 100000000 / (n - 1) + 5, MID, lastot = tot;
while (L < R) {
++T;
MID = (L + R) >> 1;
tot = lastot;
for (int i = mx + 1; i <= mx + n * 2; ++i)
firs[i] = 0;
for (int i = 1; i <= vn; ++i) firs[rep[i]] = 0;
for (int i = 1; i <= n; ++i) {
Add(rep[a[i][1]], mx + i);
Add(rep[a[i][0]], mx + n + i);
}
lb[0] = 1, rb[0] = 0;
for (int i = 1; i <= vn; ++i) {
lb[i] = lb[i - 1], rb[i] = max(rb[i - 1], i);
while (lb[i] < i && d[i] - d[lb[i]] >= MID) ++lb[i];
while (d[rb[i]] - d[i] < MID && rb[i] <= vn) ++rb[i]; --rb[i];
}
for (int i = 1; i <= n; ++i)
for (int j = 0; j < 2; ++j) {
int x = 0, y = vn + 1, w = a[i][j];
// for (int e = 19, q; e >= 0; --e) {
// q = x + (1 << e);
// if (q < w && d[w] - d[q] >= MID) x = q;
// q = y - (1 << e);
// if (q > w && d[q] - d[w] >= MID) y = q;
// }
// if (x != lb[w] - 1 || y != rb[w] + 1) puts("fail");
x = lb[w] - 1, y = rb[w] + 1;
if (x + 1 < w) sgt::Con(1, x + 1, w - 1, mx + n * j + i);
if (w + 1 < y) sgt::Con(1, w + 1, y - 1, mx + n * j + i);
}
if (doso()) L = MID + 1;
else R = MID;
}
io::write(L - 1), putchar('\n');

// TIMENOW
return 0;
}

4D

首先明确一点(欢迎指正):

  • 在平面图相关的讨论中,三角剖分图广义指极大平面图,即不能再通过添加任何边使得新的图无重边。

为什么要明确这一点?首先,“三角剖分图”和“极大平面图”不会出现在本题的题面转述和题解中。但是,“三角剖分图”这一概念出现在了题解中,但是实际上在没有说明“环是一个正多边形”之前,“三角剖分图”的说法是完全错误的。


一个圆上均匀分布着 \(n\) 个点,顺时针编号为 \(1\)\(n\)\(i\)\(i\;\mathrm{mod}\; n+1\) 之间有一条边权为 \(a_i\) 的线段。同时给出 \(m\) 条边,一条边 \((u,v,l)\) 是一条连接 \(u,v\)线段,其边权为 \(l\)。满足这些线段在端点之外不交

\(\sum_{1\le i\le j\le n}\mathrm{dist}(i,j)\)

\(n,m\le 2\times 10^5\)

考虑先将这个图补全,添加一些边权为 \(\infty\) 的线段,满足不能再额外添加任何一条线段使得线段在端点之外不交。

然后将所有线段画出来,得到一个被剖分成 \(n-2\) 个三角形的正 \(n\) 边形。考虑分治,选择一条线段将多边形分成两份,使得两边的顶点数最接近。令这个线段的两个端点为 \(u,v\),分成的两个多边形的顶点集合分别为 \(L,R\),那么可以使用单源最短路算法计算 \(u,v\) 到剩余点的最短路,设一个点 \(x\)\(u\) 的最短路为 \(f(x)\) ,到 \(v\) 的最短路为 \(g(x)\),那么就是求:

\[\sum_{x\in L}\sum_{y\in R}[\{x,y\}\cap\{u,v\}= \empty ]\min(f(x)+f(y),g(x)+g(y)) \]

这个是好求的。

然后将 \((u,v)\) 边的边权更新为 \((u,v)\) 的最短路,并分别递归到 \(L,R\) 的诱导子图中分治。

经过一些分析得到一定存在一条边使得较小一边的多边形的顶点数是 \(\frac{n}{3}\) 加减常数。

时间复杂度 \(O(n\log_2 n\log_{\frac 3 2}n)\)

分析:考虑一个三角形的三条边在三角形对侧的顶点个数分别为 \(x,y,z\)\(x+y+z=n+3\),发现如果存在 \(x,y,z\) 中的一个满足 \(> \frac{2(n+3)}{3}\),那么移动到包含这条边的另一个三角形上;如果不存在,则因为 \(x+y+z=n+3\),所以 \(x,y,z\) 中存在一个满足其值在 \([\frac{n+3}3,\frac{2(n+3)}{3}]\) 之中。

会发现一定不会重复经过一个三角形,因为移动之后这条边在新三角形中的对应顶点个数为 \(x+y+z-\max(x,y,z)<\frac n 3\)。因此一定会出现上述的不存在 \(x,y,z\) 中满足 \(>\frac{2(n+3)}3\) 的情况。因此得到结论。

Code
// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

#define ll long long

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(ll x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 2e5, inf = 0x3f3f3f3f;
int n, m, a[N + 5];
ll ans;

int pr[N + 5], nx[N + 5];

vector<vector<pair<int, int>>> to;
set<int> tomp[N + 5];
int deg[N + 5];

int dis[N + 5];
inline void Dij(int n, vector<vector<pair<int, int>>> &e, int s) {
for (int i = 0; i < n; ++i) dis[i] = inf;
dis[s] = 0;
static priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> gq;
gq.emplace(dis[s], s);
while (!gq.empty()) {
int u, ff;
tie(ff, u) = gq.top(); gq.pop();
if (ff != dis[u]) continue;
for (auto [v, w] : e[u])
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
gq.emplace(dis[v], v);
}
}
}

void doso(int n, vector<vector<pair<int, int>>> &e) {
if (n <= 3) {
for (int i = 0; i < n; ++i) {
Dij(n, e, i);
for (int j = i + 1; j < n; ++j)
ans += dis[j];
}
return ;
}
int L = 0, R = 0;
auto mnsz = [&](const int i, const int j) { return min(abs(i - j), n - abs(i - j)); };
auto dist = [&](const int i, const int j) { return (j - i + n) % n; };
for (int i = 0; i < n; ++i)
for (auto [j, _] : e[i])
if (mnsz(i, j) >= mnsz(L, R))
L = i, R = j;

vector<int> f(n), g(n);
Dij(n, e, L); for (int i = 0; i < n; ++i) f[i] = dis[i];
Dij(n, e, R); for (int i = 0; i < n; ++i) g[i] = dis[i];
vector<int> pa, pb;
for (int i = 0; i < n; ++i)
if (i != L && i != R) {
if (dist(L, i) + dist(i, R) == dist(L, R)) pa.emplace_back(i);
else pb.emplace_back(i);
}
ll da = 0, db = 0;
for (int x : pa) da += g[x];
for (int x : pb) db += g[x];
ans -= g[L];
ans += da * (ll)pb.size() + db * (ll)pa.size();
for (int i = 0; i < n; ++i) f[i] -= g[i];
sort(pa.begin(), pa.end(), [&](const int &i, const int &j) { return f[i] > f[j]; });
sort(pb.begin(), pb.end(), [&](const int &i, const int &j) { return f[i] > f[j]; });
{
int ii = (int)pa.size();
ll sum = 0, cnt = 0;
for (int x : pb) {
while (ii > 0 && f[pa[ii - 1]] + f[x] < 0) {
--ii;
sum += f[pa[ii]];
++cnt;
}
ans += cnt * f[x] + sum;
}
}
int cnt;
vector<int> id(n);
{
cnt = 0;
for (int i = 0; i < n; ++i) id[i] = -1;
for (int i = L; ; ++i) {
if (i == n) i = 0;
id[i] = cnt++;
if (i == R) break;
}
vector<vector<pair<int, int>>> tmpe(cnt);
for (int i = 0; i < n; ++i)
if (id[i] != -1)
for (auto [j, w] : e[i])
if (id[j] != -1) {
if ((i == L && j == R) || (i == R && j == L))
tmpe[id[i]].emplace_back(id[j], g[L]);
else
tmpe[id[i]].emplace_back(id[j], w);
}
doso(cnt, tmpe);
}
{
cnt = 0;
for (int i = 0; i < n; ++i) id[i] = -1;
for (int i = R; ; ++i) {
if (i == n) i = 0;
id[i] = cnt++;
if (i == L) break;
}
vector<vector<pair<int, int>>> tmpe(cnt);
for (int i = 0; i < n; ++i)
if (id[i] != -1)
for (auto [j, w] : e[i])
if (id[j] != -1) {
if ((i == L && j == R) || (i == R && j == L))
tmpe[id[i]].emplace_back(id[j], g[L]);
else
tmpe[id[i]].emplace_back(id[j], w);
}
doso(cnt, tmpe);
}
}


signed main() {
STCLOCK

freopen("circles.in", "r", stdin);
freopen("circles.out", "w", stdout);

io::read(n), io::read(m);
to.resize(n);
for (int i = 1; i <= n; ++i) {
io::read(a[i]);
to[i - 1].emplace_back(i % n, a[i]);
to[i % n].emplace_back(i - 1, a[i]);
pr[i - 1] = (i + n - 2) % n, nx[i - 1] = i % n;
}
for (int i = 1, u, v, l; i <= m; ++i) {
io::read(u), io::read(v), io::read(l);
--u, --v;
to[u].emplace_back(v, l);
to[v].emplace_back(u, l);
tomp[u].insert(v), tomp[v].insert(u);
++deg[u], ++deg[v];
}
{
queue<int> Q;
for (int i = 0; i < n; ++i)
if (deg[i] == 0)
Q.emplace(i);
while (!Q.empty()) {
int u = Q.front();
Q.pop();
if ((pr[u] - nx[u] + n) % n <= 1) continue;
nx[pr[u]] = nx[u];
pr[nx[u]] = pr[u];
if (tomp[pr[u]].count(nx[u])) {
if ((--deg[pr[u]]) == 0) Q.emplace(pr[u]);
if ((--deg[nx[u]]) == 0) Q.emplace(nx[u]);
} else {
to[pr[u]].emplace_back(nx[u], inf);
to[nx[u]].emplace_back(pr[u], inf);
}
}
}
doso(n, to);
io::write(ans), putchar('\n');

// TIMENOW
return 0;
}

Miscellaneous

Codeforces 269E - String Theory

首先,考虑一根弦的类型是不变的,那么考虑一根弦的两个顶点分别关联到题目描述操作的同一列/行,那么会得到一个关系的结构。

然后考虑目标状态和当前状态之间,考虑如果存在一一对应关系使得上述结构相同,那么必然有解。

考虑这个条件是什么,实际上就是带颜色的图同构判断,而且图由若干环组成。

显然可以 \(O(n\log_2n)\) SA 求出一个环的最小表示法,然后再用 SA 排序后判断字符串是否相同。但是很遗憾 TLE 了。而且实际上好像 \(O(n\log_2n)\) 哈希都能过/lh。然后比较暴力地,可以使用 SA-IS \(O(n)\) 求 SA 通过此题。但是实际上会发现目标状态的图的形式比较特殊,可以直接判断形式就可以 \(O(n)\) 了。

Submission #329155592 - Codeforces

Codeforces 2122G - Tree Parking

考虑一棵树的贡献,记 \(f(u)\) 表示以 \(u\) 为子树的方案数,\(s(u)\) 表示子树大小。那么应该有:

\[\begin{aligned} f(u)&=\frac{(2s(u)-1)(2s(u)-2)!}{\prod_{v\in son(u)}(2s(v))!}\prod_{v\in son(u)} f(v) \\ &= \frac{(2s(u))!}{2s(u)\prod_{v\in son(u)}(2s(v))!}\prod_{v\in son(u)} f(v) \\ f(1) &=\frac{(2n)!}{2^n\prod_{u\in T} s(u)} \end{aligned} \]

然后考虑这个 \(\frac{1}{\prod_{u\in T} s(u)}\),尝试从此入手,发现一棵树从叶子开始的拓扑序个数就是 \(\frac{n!}{\prod_{u\in T} s(u)}\),我们考虑求这个。那么就是求所有 \(k\) 个叶子的有根有标号树的拓扑序个数。

进行两种不同的思考:

  • 考虑记上述方案为 \(f(n,k)\),则有 \(f(n,k)=kf(n-1,k)+(n-k)f(n-1,k-1)\)。考虑这个形式类似欧拉数,而欧拉数可以 \(O(n)\) 计算某一项,套公式即可。
  • 考虑枚举 \(i\) 每次加入,任意接在一个位置下。然后每次遍历先访问编号最大的点得到一个 dfs 序,那么 dfs 序上的一个位置 \(i\) 是叶子当且仅当:\(i=n\)\(a_i>a_{i+1}\)。考虑任意一个 \(a\) 都能得到唯一一棵树吗?考虑如果有 \(a_{i}>a_{i+1}\),那么就找到当前到根的链上最深的一个点满足 \(a_u<a_{i+1}\),那么这个 \(u\) 一定是 \(i+1\) 的父亲,因此可以唯一得到一棵树。那么我们只需求 \(n-1\) 个数满足恰好 \(k-1\) 个位置有 \(a_i>a_{i+1}\) 的方案数即可。会发现这就是欧拉数的定义。

Submission #329920917 - Codeforces

QOJ #7403. Subset Sum

考虑 dp。先加入若干数使得 \(0\le c-sum\le v\),然后考虑要删除若干已加入的数,并加入一些未加入的数。然后如果 \(sum-c<0\) 就加入未加入,否则就删除已加入。记 \(f(i,j,v)\) 表示已加入的集合中考虑到第 \(i\) 个数,未加入的集合中考虑到第 \(j\) 个数,\(v=sum-c\)\(f(...)=[有方案]\)。转移是简单的。

那么考虑可以优化成 \(f(i,v)=j\) 表示 \(i,v\) 满足上述条件时 \(j\) 的最小值。但是此时的时空仍然是 \(O(n^2v)\) 的。那么接着考虑优化。发现每次只需要更新 \([f(i,v)+1,f(i-1,v)]\) 的所有 \(j\) 就行了。那么时间复杂度就是 \(O(nv)\) 的。

Submission #1183072 - QOJ.ac

Google Code Jam 2013 Finals

A. Graduation Requirements

考虑同时动比较麻烦,考虑可以把顺时针车看成在进来的路口挂机(必须从一个整数时刻挂机到另一个整数时刻),而逆时针车看成在每秒走两个路口,而且逆时针车经过一个路口时顺时针车不能挂机。(注意此时的逆时针车的起点和终点都发生了变化)。那么这些逆时针车在 \(q\) 时刻从 \(i\) 路口出发,走到 \(i+t\) 路口,在 \(i+t\) 这个路口的数轴上将 \(\frac t 2+q\) 这个时间变得禁止挂机。然后一个路口上的相邻的最长的整数到整数的线段对答案取 \(\max\)

然后考虑在哪些路口挂机一定不劣,发现在每个汽车的起点前的两个路口 \(st-1,st-2\),终点 \(ed\),终点前后两个路口 \(ed-1,ed+1\) 挂机一定包含了答案。这些路口的数量是 \(O(C)\) 的。

但是直接加是 \(O(C^2\log_2C)\) 的,感觉过不了(虽然应该可以过)。但是会发现固定一个终点,发现只有至多四种不同的一次函数,那么那么各自先按照截距排序,然后做归并就行了。时间复杂度 \(O(C^2)\)

Code

// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

#define int long long

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 1e3;
int rn, LM, n, os[N + 5], oe[N + 5], ot[N + 5], ans;
int pos[N * 5 + 5], cnt, id[N + 5];
int av[4][N + 5], cv[4];

inline int dis(int x, int y) { return (y - x + rn) % rn; }

inline void Calc() {
static int rv[4];
for (int o = 0; o < 4; ++o) rv[o] = 0;
int las = 0;
while (rv[0] < cv[0] || rv[1] < cv[1] || rv[2] < cv[2] || rv[3] < cv[3]) {
int ob = -1;
for (int i = 0; i < 4; ++i)
if (rv[i] < cv[i]) {
if (ob == -1) ob = i;
else
if (av[ob][rv[ob]] > av[i][rv[i]]) ob = i;
}
int t = av[ob][rv[ob]];
if (t & 1) {
ans = max(ans, min(t / 2, LM) - las);
las = t / 2 + 1;
} else {
ans = max(ans, min(t / 2 - 1, LM) - las);
las = t / 2 + 1;
}
++rv[ob];
}
ans = max(ans, LM - las);
}

inline void ARKNIGHTS() {
io::read(n), io::read(LM), io::read(rn);

cnt = 0;
for (int i = 0; i < n; ++i) {
io::read(os[i]), io::read(oe[i]), io::read(ot[i]);
--os[i], --oe[i];
oe[i] = dis(os[i], oe[i]);
os[i] = (os[i] + ot[i]) % rn;
pos[cnt++] = (os[i] + rn - 1) % rn;
pos[cnt++] = (os[i] + rn - 2) % rn;

pos[cnt++] = (os[i] + oe[i] * 2) % rn;
pos[cnt++] = (os[i] + oe[i] * 2 - 1) % rn;

pos[cnt++] = (os[i] + oe[i] * 2 + 1) % rn;
id[i] = i;
}
pos[cnt++] = 0;
sort(pos, pos + cnt);
sort(id, id + n, [](const int &i, const int &j) {
return - os[i] + ot[i] * 2 < - os[j] + ot[j] * 2;
});
cnt = unique(pos, pos + cnt) - pos;

ans = 0;
for (int i = 0; i < cnt; ++i) {
for (int o = 0; o < 4; ++o) cv[o] = 0;
for (int j = 0, u; j < n; ++j) {
u = id[j];
if (os[u] <= pos[i]) {
if (dis(os[u], pos[i]) <= 2ll * oe[u]) av[0][cv[0]++] = dis(os[u], pos[i]) + ot[u] * 2;
if (dis(os[u], pos[i]) + rn <= 2ll * oe[u]) av[2][cv[2]++] = dis(os[u], pos[i]) + rn + ot[u] * 2;
} else {
if (dis(os[u], pos[i]) <= 2ll * oe[u]) av[1][cv[1]++] = dis(os[u], pos[i]) + ot[u] * 2;
if (dis(os[u], pos[i]) + rn <= 2ll * oe[u]) av[3][cv[3]++] = dis(os[u], pos[i]) + rn + ot[u] * 2;
}
}
// printf("<%d %d>\n", i, pos[i]);
// for (int o = 0; o < 4; ++o, putchar('\n'))
// for (int j = 0; j < cv[o]; ++j)
// io::write(av[o][j]), putchar(' ');
Calc();
}
io::write(ans), putchar('\n');
}

signed main() {
STCLOCK

// freopen("sample_ts1_input.txt", "r", stdin);
// freopen("in", "r", stdin);
// freopen("ts2_input.txt", "r", stdin);
// freopen("out", "w", stdout);

for (int T = io::read(), C = 1; C <= T; ARKNIGHTS(), ++C)
printf("Case #%lld: ", C);

// TIMENOW
return 0;
}

D. Can't Stop

最慢做法/lh。

考虑其实可以线段树维护区间内集合大小 \(\le 3\) 的所有合法解,但是此时常数过于巨大。那么考虑维护集合大小 \(\le 2\) 的所有合法解,并枚举剩下的一个数 \(x\),在线段树上把包含 \(x\) 的位置删除,然后从某个 \(x\) 出发,线段树二分直到找到不存在集合大小 \(\le 2\) 合法解。

时间复杂度 \(O(nd^3\log_2 n)\) 实际上可以过。

Code
 
// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

#define ll long long

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 1e5, D = 4, NL = (1 << 19) - 1, L = 19;
int n, d, q, a[N + 5][D];

namespace Map {
const int mod = 1e7 + 7;
ll rep[mod];
int ton[mod];
inline int &mp(const ll x) {
int i = x % mod;
while (rep[i] && rep[i] != x) (++i) == mod ? i = 0 : i;
if (!rep[i]) rep[i] = x;
return ton[i];
}
inline bool mpcount(const ll x) {
int i = x % mod;
while (rep[i] && rep[i] != x) (++i) == mod ? i = 0 : i;
if (!rep[i]) return false;
return true;
}
inline void era(const ll x) {
int i = x % mod;
while (rep[i] != x) (++i) == mod ? i = 0 : i;
ton[i] = rep[i] = 0;
}
} using Map::mp, Map::era, Map::mpcount;
inline ll mkp(int x, int y) {
if (x > y) swap(x, y);
return ((ll)x) << L | y;
}
struct Set {
ll s[16]; int sz;
Set() { sz = -1; }
};
inline Set Merge(const Set &A, const Set &B) {
if (A.sz == -1) return B;
if (B.sz == -1) return A;
static Set res; res.sz = 0;
static int tmpA[4], tmpB[4], sa, sb;
sa = 0, sb = 0;
for (int i = 0; i < A.sz; ++i) {
++mp(A.s[i]);
if ((A.s[i] & NL) == A.s[i]) tmpA[sa++] = A.s[i];
}
for (int i = 0; i < B.sz; ++i) {
++mp(B.s[i]);
if ((B.s[i] & NL) == B.s[i]) tmpB[sb++] = B.s[i];
}
for (int i = 0; i < A.sz; ++i)
if ((A.s[i] & NL) != A.s[i]) {
if (mp(A.s[i]) == 2) res.s[res.sz++] = A.s[i];
else {
int x = A.s[i] >> L, y = A.s[i] & NL;
if (mpcount(x) || mpcount(y)) res.s[res.sz++] = A.s[i];
}
}
for (int i = 0; i < B.sz; ++i)
if ((B.s[i] & NL) != B.s[i])
if (mp(B.s[i]) == 1) {
int x = B.s[i] >> L, y = B.s[i] & NL;
if (mpcount(x) || mpcount(y)) res.s[res.sz++] = B.s[i];
}
for (int i = 0; i < sa; ++i)
if (mp(tmpA[i]) == 2) res.s[res.sz++] = tmpA[i];
else {
for (int j = 0; j < sb; ++j)
if (mp(tmpB[j]) == 1 && !mpcount(mkp(tmpA[i], tmpB[j])))
res.s[res.sz++] = mkp(tmpA[i], tmpB[j]);
}
for (int i = B.sz - 1; i >= 0; --i)
if (mpcount(B.s[i])) era(B.s[i]);
for (int i = A.sz - 1; i >= 0; --i)
if (mpcount(A.s[i])) era(A.s[i]);
return res;
}

namespace sgt {
#define lson(p) ((p) << 1)
#define rson(p) ((p) << 1 | 1)
const int P = N << 2;
int lt[P], rt[P];
Set qt[P];
inline void push_up(int p) { qt[p] = Merge(qt[lson(p)], qt[rson(p)]); }
void Build(int p, int l, int r) {
lt[p] = l, rt[p] = r;
if (l == r) {
qt[p].sz = 0;
for (int i = 0; i < d; ++i)
if (i == 0 || a[l][i - 1] != a[l][i])
qt[p].s[qt[p].sz++] = a[l][i];
return ;
}
int mid = (l + r) >> 1;
Build(lson(p), l, mid), Build(rson(p), mid + 1, r);
push_up(p);
}
void Mdf(int p, int x, int o) {
if (lt[p] == rt[p]) {
if (o == -1) qt[p].sz = -1;
else {
qt[p].sz = 0;
for (int i = 0; i < d; ++i)
if (i == 0 || a[lt[p]][i - 1] != a[lt[p]][i])
qt[p].s[qt[p].sz++] = a[lt[p]][i];
}
return ;
}
int mid = (lt[p] + rt[p]) >> 1;
if (x <= mid) Mdf(lson(p), x, o);
else Mdf(rson(p), x, o);
push_up(p);
}
int Que(int p, int x, Set &tmp) {
if (lt[p] == rt[p]) {
tmp = Merge(tmp, qt[p]);
return tmp.sz == 0 ? rt[p] : rt[p] + 1;
}
int mid = (lt[p] + rt[p]) >> 1;
if (x >= lt[p]) {
if (x <= mid) {
int r = Que(lson(p), x, tmp);
if (tmp.sz == 0) return r;
Set qq = Merge(tmp, qt[rson(p)]);
if (qq.sz == 0) return Que(rson(p), x, tmp);
tmp = qq;
return rt[p] + 1;
}
return Que(rson(p), x, tmp);
} else {
Set qq = Merge(tmp, qt[lson(p)]);
if (qq.sz == 0) return Que(lson(p), x, tmp);
return Que(rson(p), x, tmp = qq);
}
}
}

vector<int> pos[N + 5];

inline void ARKNIGHTS() {
io::read(n), io::read(d), io::read(q);
for (int i = 1; i <= N; ++i) pos[i].clear();
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < d; ++j) io::read(a[i][j]);
sort(a[i], a[i] + d);
for (int j = 0; j < d; ++j)
if (j == 0 || a[i][j - 1] != a[i][j])
pos[a[i][j]].emplace_back(i);
}
sgt::Build(1, 1, n);
int ansl = 1, ansr = 1;
if (q == 3) {
for (int va = 1; va <= N; ++va) {
for (int i : pos[va]) sgt::Mdf(1, i, -1);
for (int i : pos[va]) {
Set tmp; tmp.sz = -1;
int j = sgt::Que(1, i, tmp) - 1;
if (ansr - ansl < j - i) ansl = i, ansr = j;
else if (ansr - ansl == j - i && i < ansl) ansl = i, ansr = j;
}
for (int i : pos[va]) sgt::Mdf(1, i, 1);
}
} else {
for (int i = 1; i <= n; ++i) {
Set tmp; tmp.sz = -1;
int j = sgt::Que(1, i, tmp) - 1;
if (ansr - ansl < j - i) ansl = i, ansr = j;
else if (ansr - ansl == j - i && i < ansl) ansl = i, ansr = j;
}
}
io::write(ansl - 1), putchar(' ');
io::write(ansr - 1), putchar('\n');
}

signed main() {
STCLOCK

// freopen("sample_ts1_input.txt", "r", stdin);
// freopen("ts1_input.txt", "r", stdin);
// freopen("ts2_input.txt", "r", stdin);
// freopen("in", "r", stdin);
// freopen("out", "w", stdout);

for (int T = io::read(), C = 1; T--; ++C, ARKNIGHTS())
printf("Case #%d: ", C);

TIMENOW
return 0;
}

E. Let Me Tell You a Story

考虑记 \(f(x)\) 表示长度为 \(x\) 的不升序列的个数。

那么考虑恰好删到剩余 \(x\) 个时结束的方案数就是 \((n-x)!f(x)-(x+1)(n-x-1)!f(x+1)\)。然后求 \(f(x)\) 可以 \(O(n\log_2 n)\) 树状数组求。那么总的时间复杂度就是 \(O(n^2\log_2 n)\)

Code

// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

#define int uint16_t

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 8e3, mod = 1e4 + 7;
int n, vn, a[N + 5], f[N + 5], jc[N + 5], g[N + 5];

bool nw[N + 5];

inline int& MOD(int &x) { return x >= mod ? x -= mod : x; }
inline int mul(int x, int y) { return 1 * x * y % mod; }

namespace BIT {
inline int lowbit(const signed x) { return x & -x; }
int c[N + 5];
inline void Upd(int p, int x) {
while (p <= vn) MOD(c[p] += x), p += lowbit(p);
}
inline int Que(int p) {
static int res; res = 0;
while (p > 0) MOD(res += c[p]), p -= lowbit(p);
return res;
}
}

inline void ARKNIGHTS() {
io::read(n);
for (int i = 1; i <= n; ++i) io::read(a[i]);
{
vector<int> disc;
for (int i = 1; i <= n; ++i) disc.emplace_back(a[i]);
sort(disc.begin(), disc.end());
disc.erase(unique(disc.begin(), disc.end()), disc.end());
for (int i = 1; i <= n; ++i)
a[i] = lower_bound(disc.begin(), disc.end(), a[i]) - disc.begin() + 1;
vn = (int)disc.size();
}
jc[0] = 1;
for (int i = 1; i <= n; ++i) jc[i] = mul(jc[i - 1], i), f[i] = 0, g[i] = 1, nw[i] = true;

int ans = f[1] = jc[n];
for (int L = 2; L <= n; ++L) {
for (int i = 1; i <= vn; ++i) BIT::c[i] = 0;
bool flg = false;
int mn = vn + 1;
for (int i = n; i >= 1; --i)
if (nw[i]) {
if (!(nw[i] = (mn <= a[i]))) mn = a[i];
flg = true;
int tmp = g[i];
g[i] = BIT::Que(a[i]);
MOD(f[L] += g[i]);
if (tmp) BIT::Upd(a[i], tmp);
}
f[L] = mul(f[L], jc[n - L]);
MOD(ans += mod - mul(L - 1, f[L]));
if (!flg) break;
}
io::write(ans), putchar('\n');
}

signed main() {
STCLOCK

for (int T = io::read(), Csnow = 1; T--; Csnow++, ARKNIGHTS())
printf("Case #%d: ", Csnow);

// TIMENOW
return 0;
}

HDU2025 暑期多校 Round 2(选)

1001

考虑分圆多项式。题目相当于求 \(f(x)g(x)=\left(\frac{x^n-1}{x-1}\right)^2\),且 \(\forall i:[x^i]f(x)\ge 0,[x^i]g(x)\ge 0\),且 \(f(1)=g(1)=n\)。考虑分圆多项式 \(\Phi_{i}(x)\),有:

\[\left(\frac{x^n-1}{x-1}\right)^2=\prod_{i|n,i>1}\Phi_i^2(x) \]

已知分圆多项式是 \(Z[x]\) 中的不可约项,因此可以搜索加剪枝打出一个表。。

时间复杂度 \(O(3^{d(n)/2}n^2)\)。实际上很快。

Code
// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 240, LN = 120;
int n;

inline array<int, N + 5> Div(array<int, N + 5> f, array<int, N + 5> g) {
array<int, N + 5> ans;
int gl = 0;
for (int i = 0; i <= N; ++i) {
if (g[i]) gl = i;
ans[i] = 0;
}
for (int i = N; i >= gl; --i)
if (f[i] != 0) {
ans[i - gl] = f[i];
for (int j = i; j >= i - gl; --j)
f[j] -= ans[i - gl] * g[gl - i + j];
}
return ans;
}

array<int, N + 5> Phi[N + 5];
int pv[N + 5], len[N + 5];
inline void init() {
for (int i = 1; i <= LN; ++i) {
Phi[i][i] = 1, Phi[i][0] = -1;
for (int j = 1; j < i; ++j)
if (i % j == 0)
Phi[i] = Div(Phi[i], Phi[j]);
pv[i] = 0, len[i] = 0;
for (int j = 0; j <= i; ++j) {
pv[i] += Phi[i][j];
if (Phi[i][j] != 0) len[i] = j;
}
}
}

int du[N + 5], cntd;
bool canv[N + 5][N + 5];

array<int, N + 5> A[N + 5], tA[N + 5][3], B[N + 5], tB[N + 5][3];
int va, vb, ans;

void dfs(int u) {
if (u == 0) {
// for (int i = 0; i <= n * 2; ++i) printf("%d ", A[1][i]); puts("");
// for (int i = 0; i <= n * 2; ++i) printf("%d ", B[1][i]); puts("");
// puts("");
if (va != n || vb != n) return ;
for (int i = 0; i <= n * 2; ++i)
if (A[1][i] < 0 || B[1][i] < 0) return ;
++ans;
return ;
}
if (n % va != 0 || n % vb != 0) return ;
if (!canv[u][n / va]) return ;
for (int i = 0; i <= n * 2; ++i)
tA[u][0][i] = A[u + 1][i], tB[u][0][i] = B[u + 1][i];
for (int i = 1; i < 3; ++i) {
for (int j = 0; j <= n * 2; ++j)
tA[u][i][j] = tB[u][i][j] = 0;
for (int j = 0; j <= n * 2; ++j) if (Phi[du[u]][j])
for (int k = 0; j + k <= n * 2; ++k)
tA[u][i][j + k] += Phi[du[u]][j] * tA[u][i - 1][k],
tB[u][i][j + k] += Phi[du[u]][j] * tB[u][i - 1][k];
}
vb *= pv[du[u]] * pv[du[u]] * pv[du[u]];
for (int i = 0; i < 3; ++i) {
for (int j = 0; j <= n * 2; ++j)
A[u][j] = tA[u][i][j], B[u][j] = tB[u][2 - i][j];
vb /= pv[du[u]];
dfs(u - 1);
va *= pv[du[u]];
}
va /= pv[du[u]] * pv[du[u]] * pv[du[u]];
}

inline int sol(int nn) {
n = nn;
cntd = 0;
for (int i = 2; i <= n; ++i)
if (n % i == 0)
du[++cntd] = i;
sort(du + 1, du + cntd + 1, [](const int &x, const int &y) { return pv[x] < pv[y]; });
for (int i = 1; i <= n; ++i) canv[0][i] = false;
canv[0][1] = true;
for (int i = 1, u; i <= cntd; ++i) {
u = du[i];
for (int j = n; j >= 1; --j) {
canv[i][j] = canv[i - 1][j];
if (canv[i - 1][j] && j * pv[u] <= n) canv[i][j * pv[u]] = true;
if (canv[i - 1][j] && j * pv[u] * pv[u] <= n) canv[i][j * pv[u] * pv[u]] = true;
}
}
// printf("%d\n", canv[1][2]);
for (int i = 1; i <= N; ++i) A[cntd + 1][i] = B[cntd + 1][i] = 0;
A[cntd + 1][0] = B[cntd + 1][0] = 1;
va = 1, vb = 1; ans = 0;
dfs(cntd);
return ans;
}

int res[N + 5] = {0, 1, 1, 1, 3, 1, 3, 1, 7, 3, 3, 1, 15, 1, 3, 3, 19, 1, 15, 1, 15, 3, 3, 1, 65, 3, 3, 7, 15, 1, 25, 1, 51, 3, 3, 3, 113, 1, 3, 3, 65, 1, 25, 1, 15, 15, 3, 1, 279, 3, 15, 3, 15, 1, 65, 3, 65, 3, 3, 1, 249, 1, 3, 15, 141, 3, 25, 1, 15, 3, 25, 1, 695, 1, 3, 15, 15, 3, 25, 1, 279, 19, 3, 1, 243, 3, 3, 3, 65, 1, 235, 3, 15, 3, 3, 3, 1165, 1, 15, 15, 117, 1, 25, 1, 65, 25, 3, 1, 697, 1, 25, 3, 279, 1, 25, 3, 15, 15, 3, 3, 1911};

signed main() {
STCLOCK

// init();
// for (int i = 1; i <= LN; ++i) printf("%d, ", sol(i));
for (int T = io::read(); T--; )
io::write(res[io::read()]), putchar('\n');

// TIMENOW
return 0;
}

HDU2025 暑期多校 Round 3(选)

1004

考虑一个匹配数 \(Q\) 是否合法。

如果每个数被用了 \(b_i\) 个三,则剩 \(c_i=a_i-3b_i\) 个一。有 \(A=\sum a,\;Q=B=\sum b,\;C=\sum c\)

考虑有若干限制:

  • \(\forall i\to b_i \le \lfloor \frac {a_i} 3 \rfloor\)。显然。
  • \(B\le C\to Q\le \lfloor \frac A 4 \rfloor\)。显然。
  • \(\forall i\to b_i+c_i\le C\to a_i-2b_i\le C\to b_i \ge \lceil \frac {a_i-A+3Q} 2\rceil\)\(b_i+c_i\le C\) 时显然可以构造答案。而 \(\exists i\to b_i+c_i>C\) 时显然无解。

因此有 \(Q\le \lfloor\frac{A}{4}\rfloor,\;\forall i\to \lceil \frac{a_i-A+3Q}{2}\rceil\le b_i\le \lfloor \frac{a_i}{3}\rfloor\)。发现 \(Q\) 可以二分。

HDU2025 暑期多校 Round 4(选)

1010

(下文 \(\oplus\) 指异或运算)

\(f(x)\) 表示异或和为 \(x\) 的集合个数,\(g(...)\) 表示题面中的 \(f(...)\)

首先的一点是,如果 \(n\) 是奇数,那么答案一定就是总方案数除以 \(2^m\),因为可以整体 \(\oplus x\),使得集合的异或和也 \(\oplus x\)

那么考虑 \(n\) 是奇数的情况。对于一个 \(x\) 考虑计算 \(f(0) - f(x)\) 。按照 \((u,u\oplus x)\) 的方式配对,显然在值域上可以配成 \(2^{m-1}\) 个不交的对。考虑在集合中,找到最小的 \(u\) 满足 \(u\)\(u\oplus x\) 的总个数为奇数,那么把集合中所有的 \(u\)\(u\oplus x\) 全部 \(\oplus x\),发现异或和也 \(\oplus x\)。那么这种找的到 \(u,u\oplus x\) 总个数为奇数的集合,就可以在 \(f(0)\)\(f(x)\) 之间构成双射。否则所有 \(u,u\oplus x\) 总个数为偶数,此时异或和可以计算为:出现个数为奇数的 \(u\) 的个数除以 \(2\) 是奇数时为 \(x\);否则为 \(0\)

发现 \(\forall x,y>0\to f(0)-f(x)=f(0)-f(y)\to f(x)=f(y)\)。那么就只需要计算一个 \(f(0)-f(x)\) 以及 \(\sum_{i=0}^{2^m-1}f(i)\) 即可。

那么考虑 \(F(z)\) 是奇数+奇数的生成函数,而 \(G(z)\) 是偶数+偶数的生成函数,则应该有:

\[\begin{aligned} f(0)-f(x)=&[z^n]\sum_{i=0}^{2^{m-1}} (-1)^iF(z)^iG(z)^{2^{m-1}-i}{2^{m-1}\choose i} \\ =&[z^n](G(z)-F(z))^{2^{m-1}} \end{aligned} \]

稍加分析得到:

\[G(z)-F(z)=\begin{cases} (1+z^2+z^4+\cdots+z^{2k}) & 2\mid k \\ (1+z^2+z^4+\cdots+z^{k-1}-z^{k+1}-z^{k+3}-\cdots-z^{2k})=(1-z^{k+1})(1+z^2+\cdots+z^{k-1}) & 2\nmid k \end{cases} \]

那么考虑通过式子计算 \(S\) 为总方案数,\(W_0,W_1\)\(k\) 为偶数或奇数时的 \(f(0)-f(x)\)

\[\begin{aligned} S=&\sum_{i=0}^{\left\lfloor \frac{n}{k+1}\right\rfloor}(-1)^i {n-i(k+1)+2^{m}-1 \choose 2^{m}-1}{2^{m} \choose i} \\ W_0=&\sum_{i=0}^{\left\lfloor\frac{\frac{n}{2}}{k+1} \right\rfloor} (-1)^i {\frac{n}{2} - i(k+1)+2^{m-1}-1\choose 2^{m-1}-1}{2^{m-1}\choose i} \\ W_1=&\sum_{i=0}^{\left\lfloor\frac{\frac{n}{2}}{k+1} \right\rfloor} (-1)^i {\frac{n}{2} - \frac{i(k+1)}{2}+2^{m-1}-1\choose 2^{m-1}-1}{2^{m}\choose i} \end{aligned} \]

\(S\) 的求法较简单。\(W_0\)\(W_1\) 的求法考虑 \(G(z)-F(z)\) 的形式把 \(z\) 的指数除以 \(2\)\(W_0\) 钦定 \(2^{m-1}\) 幂次中多少 \(>k\) 并容斥。而 \(W_1\) 类似 \(W_0\),只是因为多了 \((1-z^{(k+1)/2})\) 这项,所以\(-z^{(k+1)/2}\) 的贡献可以从 \(2^m\) 个多项式中获得,因此相当于钦定 \(2^{m}\) 个多项式中多少 \(>k\)

\(W\)\(k\) 为偶数时为 \(W_0\),否则为 \(W_1\)。应该有:

\[f(0)=\begin{cases} \frac{S}{2^m} & 2\nmid n \\ \frac{S-W(2^m-1)}{2^m}=\frac{S-W}{2^m}+W & 2\mid n \end{cases} \]

发现这样的时间复杂度是 \(O(n/k)\) 的/jy,于是求 \(g(n,m,\le n)\) 的时间复杂度是 \(O(n\ln n)\) 的,就可以过了。

Code
// Go in my style.
// Not afraid to dark.

#include <bits/stdc++.h>
using namespace std;

clock_t sttime;
#define STCLOCK sttime = clock();
#define TIMENOW fprintf(stderr, "\nNOW TIME COSSEMED: %0.4lf\n", 1.0 * (clock() - sttime) / CLOCKS_PER_SEC);
#define inline __inline__ __attribute__ ((always_inline))

#define int long long

namespace io {
int pos;
inline int read(int &p = pos) {
static bool v; static char c;
p = 0, v = false, c = getchar();
while (!isdigit(c)) {
if (c == '-') v = true;
c = getchar();
}
while (isdigit(c)) {
p = (p << 1) + (p << 3) + (c - 48);
c = getchar();
}
return p = v ? - p : p;
}
inline void write(int x) {
static int sta[65], top; top = 0;
if (x < 0) putchar('-'), x = - x;
do sta[++top] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[top--] + 48);
}
}

const int N = 1e7, M = 23, mod = 1e9 + 7;
int n, m, k;
int jc[N * 2 + 5], inv[N * 2 + 5], inj[N * 2 + 5];
int ipw[M + 5];

inline int C(int a, int b) { return a >= b ? jc[a] * inj[b] % mod * inj[a - b] % mod : 0; }

inline int Calc(int n, int m, int k) {
int S = 0, W = 0;
for (int i = n / (k + 1); i >= 0; --i)
S = (C(n - (k + 1) * i + (1 << m) - 1, (1 << m) - 1) * C(1 << m, i) - S + mod) % mod;
if (k & 1) {
for (int i = (n / 2) / ((k + 1) / 2); i >= 0; --i)
W = (C(n / 2 - (k + 1) / 2 * i + (1 << (m - 1)) - 1, (1 << (m - 1)) - 1) * C(1 << m, i) - W + mod) % mod;
} else {
for (int i = (n / 2) / (k + 1); i >= 0; --i)
W = (C(n / 2 - (k + 1) * i + (1 << (m - 1)) - 1, (1 << (m - 1)) - 1) * C(1 << (m - 1), i) - W + mod) % mod;
}
if (n & 1) return S * ipw[m] % mod;
return ((S - W + mod) * ipw[m] + W) % mod;
}

inline void ARKNIGHTS() {
io::read(n), io::read(m), io::read(k);
io::write(Calc(n, m, k)), putchar('\n');
io::read(n), io::read(m);
int Xor = 0, Sum = 0;
for (int k = 1, x; k <= n; ++k) {
x = Calc(n, m, k);
Xor ^= x;
Sum = (Sum + x * x) % mod;
}
io::write(Xor), putchar(' '),
io::write(Sum), putchar('\n');
}

signed main() {
STCLOCK

jc[0] = jc[1] = inv[1] = inj[0] = inj[1] = 1;
for (int i = 2; i <= N * 2; ++i) {
jc[i] = jc[i - 1] * i % mod;
inv[i] = inv[i - mod % i] * (mod / i + 1) % mod;
inj[i] = inj[i - 1] * inv[i] % mod;
}
ipw[0] = 1;
for (int i = 1; i <= M; ++i) ipw[i] = ipw[i - 1] * inv[2] % mod;

for (int T = io::read(); T--; ARKNIGHTS()) ;

// TIMENOW
return 0;
}
posted @ 2025-08-03 17:31  saubguiu  阅读(19)  评论(0)    收藏  举报