爆零力。

分析

T1

给定 $S=n^n,n\in\mathbb{N^{*}}$ $n$

用的 NTT,OJ 的评测机太慢了,常数爆炸。

正解是当 $n>2$ 时,每一个 $n^n$ 位数都不同,且等于 $\left\lfloor n\log_{10}n\right\rfloor + 1$ ,然后二分。


const int N = 3e5 + 5;

inline ll Read() {
    ll x = 0, f = 1;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-')
        f = -f, c = getchar();
    while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    return x * f;
}

namespace NTT {
const ll mod = 998244353ll, G = 3, invG = 332748118ll;
int n, m;
int tr[N << 1];
ll f[N << 1], g[N << 1];

ll qpow(ll a, ll b) {
    ll ans = 1;
    for (; b; b >>= 1, a = a * a % mod) ans = ans * (b & 1 ? a : 1) % mod;
    return ans;
}

void NTT(ll *f, bool isDFT) {
    for (int i = 1; i <= n; i++)
        if (i < tr[i])
            swap(f[i], f[tr[i]]);
    for (int p = 2; p <= n; p <<= 1) {
        int len = p >> 1;
        ll omega = qpow(isDFT ? G : invG, (mod - 1) / p);
        for (int k = 0; k < n; k += p) {
            ll tmp = 1ll;
            for (int i = k; i < k + len; i++) {
                ll y = tmp * f[i + len] % mod;
                f[i + len] = (f[i] - y + mod) % mod;
                f[i] = (f[i] + y) % mod;
                tmp = tmp * omega % mod;
            }
        }
    }
    if (!isDFT) {
        ll invn = qpow(n, mod - 2);
        for (int i = 0; i <= n; i++) f[i] = f[i] * invn % mod;
    }
}

void main(int _n, int _m) {
    n = _n, m = _m;
    for (m += n, n = 1; n <= m; n <<= 1)
        ;
    for (int i = 1; i <= n; i++) tr[i] = (tr[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);

    NTT(f, 1), NTT(g, 1);

    for (int i = 0; i <= n; i++) f[i] = f[i] * g[i];

    NTT(f, 0);
}
}  // namespace NTT

struct Number {
    int val[N];
    void operator=(int b) {
        for (; val[0]; val[val[0]--] = 0)
            ;
        for (val[0] = 0; b; b /= 10) {
            val[++val[0]] = b % 10;
        }
        return;
    }
    Number operator*(Number b) {
        memset(NTT::f, 0, sizeof NTT::f);
        memset(NTT::g, 0, sizeof NTT::g);
        for (int i = 1; i <= val[0]; i++) NTT::f[i - 1] = val[i];
        for (int i = 1; i <= b.val[0]; i++) NTT::g[i - 1] = b.val[i];
        NTT::main(val[0] - 1, b.val[0] - 1);
        Number c;
        c.val[0] = NTT::m + 1;
        int d = 0, v = 0, maxLen = c.val[0];
        for (int i = 1; i <= c.val[0] || v; i++) {
            d = NTT::f[i - 1] + v;
            c.val[i] = d % 10;
            v = d / 10;
            maxLen = max(maxLen, i);
        }
        c.val[0] = maxLen;
        return c;
    }
} n, tmp;
Number operator^(Number a, int b) {
    Number ans;
    ans = 1;
    for (; b; b >>= 1, a = a * a)
        if (b & 1)
            ans = ans * a;
    return ans;
}

char s[N];
int len;

int check(int x) {
    int tmp = 1.0 * x * log10(x);
    tmp++;
    return tmp > len;
}

int main() {
    //	freopen(".in", "r", stdin);
    //	freopen(".out", "w", stdout);
    scanf("%s", s + 1);
    len = strlen(s + 1);
    if (len == 1 && s[1] == '1') {
        puts("1");
        return 0;
    }
    if (len == 1 && s[1] == '0') {
        puts("0");
        return 0;
    }
    if (len == 1 && s[1] == '4') {
        puts("2");
        return 0;
    }
    int l = 0, r = 65535, ans = 0;
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid))
            r = mid - 1;
        else
            l = mid + 1, ans = mid;
    }
    printf("%d\n", ans);
    return 0;
}


T2

动态,在给定点集中,找树的直径。

其中用到 $\mathcal{O}(1)$ LCA,方法是用欧拉序(DFS 序,但重复访问的点重复加入序里)转为序列,然后 ST 表求两点间深度最小的点。

贴个没过的代码:

const int N = 1e5 + 5;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, q;
int head[N], tot;
struct edge {
	int to, nxt;
}e[N << 1];
void Add(int u, int v) {
	e[++tot] = (edge) {v, head[u]}, head[u] = tot;
}
int dep[N], dfn, eln;
int a[N << 1], b[N], f[N][25];
int dpos[N], epos[N];
void dfs(int u, int fa) {
	dep[u] = dep[fa] + 1;
	f[u][0] = u;
	a[++eln] = u;
	b[++dfn] = u;
	dpos[u] = dfn;
	epos[u] = eln;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v == fa) continue;
		dfs(v, u);
		a[++eln] = u;
	}
}

int LCA(int u, int v) {
	u = epos[u], v = epos[v];
	if (u > v) u ^= v ^= u ^= v;
	int len = log2(v - u + 1);
	if (dep[f[u][len]] < dep[f[v - (1 << len) + 1][len]]) return f[u][len];
	return f[v - (1 << len) + 1][len];
}
int distance (int u, int v) { return 2 * dep[LCA(u, v)] - dep[u] - dep[v]; }

int type[N];
struct SegmentTree {
	struct Tree {
		int l, r, p[2];
	}t[N << 2];

	void PushUp (int p) {
		int p1, p2, dis = 0, flag = 0;
		if (!type[t[p << 1].p[0]] && !type[t[p << 1].p[1]] && dis < distance(t[p << 1].p[0], t[p << 1].p[1])) dis = distance(t[p << 1].p[0], t[p << 1].p[1]), p1 = t[p << 1].p[0], p2 = t[p << 1].p[1], flag = 1;
		if (!type[t[p << 1 | 1].p[0]] && !type[t[p << 1].p[1]] && dis < distance(t[p << 1 | 1].p[0], t[p << 1].p[1])) dis = distance(t[p << 1 | 1].p[0], t[p << 1].p[1]), p1 = t[p << 1 | 1].p[0], p2 = t[p << 1].p[1], flag = 1;
		if (!type[t[p << 1 | 1].p[0]] && !type[t[p << 1].p[0]] && dis < distance(t[p << 1 | 1].p[0], t[p << 1].p[0])) dis = distance(t[p << 1 | 1].p[0], t[p << 1].p[0]), p1 = t[p << 1 | 1].p[0], p2 = t[p << 1].p[0], flag = 1;
		if (!type[t[p << 1].p[0]] && !type[t[p << 1 | 1].p[1]] && dis < distance(t[p << 1].p[0], t[p << 1 | 1].p[1])) dis = distance(t[p << 1].p[0], t[p << 1 | 1].p[1]), p1 = t[p << 1].p[0], p2 = t[p << 1 | 1].p[1], flag = 1;
		if (!type[t[p << 1].p[1]] && !type[t[p << 1 | 1].p[1]] && dis < distance(t[p << 1].p[1], t[p << 1 | 1].p[1])) dis = distance(t[p << 1].p[1], t[p << 1 | 1].p[1]), p1 = t[p << 1].p[1], p2 = t[p << 1 | 1].p[1], flag = 1;
		if (!type[t[p << 1 | 1].p[0]] && !type[t[p << 1 | 1].p[1]] && dis < distance(t[p << 1 | 1].p[0], t[p << 1 | 1].p[1])) 
			dis = distance(t[p << 1 | 1].p[0], t[p << 1 | 1].p[1]), p1 = t[p << 1 | 1].p[0], p2 = t[p << 1 | 1].p[1], flag = 1;
		if (!flag) {
			if (!type[t[p << 1].p[0]]) p1 = p2 = t[p << 1].p[0], flag = 1;
			if (!type[t[p << 1].p[1]]) p1 = p2 = t[p << 1].p[1], flag = 1;
			if (!type[t[p << 1 | 1].p[0]]) p1 = p2 = t[p << 1 | 1].p[0], flag = 1;
			if (!type[t[p << 1 | 1].p[1]]) p1 = p2 = t[p << 1 | 1].p[1], flag = 1;
		} 
		if (!flag) p1 = p2 = t[p << 1].p[0];
		t[p].p[0] = p1, t[p].p[1] = p2;
	}
	void Build(int p, int l, int r) {
		t[p].l = l, t[p].r = r;
		if (t[p].l == t[p].r) {
			t[p].p[0] = t[p].p[1] = b[t[p].l];
			return;
		}
		int mid = t[p].l + t[p].r >> 1;
		Build (p << 1, l, mid);
		Build (p << 1 | 1, mid + 1, r);
		PushUp(p);
	}
	void Modify(int p, int x) {
		if (t[p].l == t[p].r) {
			type[x] ^= 1;
			return;
		}
		int mid = t[p].l + t[p].r >> 1;
		if (x <= mid) Modify (p << 1, x);
		else Modify (p << 1 | 1, x);
		PushUp(p);
	}
}t;

int main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	n = Read(), q = Read();
	for (int i = 1; i < n; i++) {
		int u = Read(), v = Read();
		Add(u, v), Add(v, u);
	}
	dfs(1, 0);
	for (int j = 1; j <= 22; j++)
		for (int i = 1; i + (1 << j) <= eln; i++)
			if (dep[f[i][j-1]] < dep[f[i + (1 << j - 1)][j-1]]) f[i][j] = f[i][j-1];
			else f[i][j] = f[i + (1 << j-1)][j-1];
	t.Build(1, 1, n);
//	return 0;
	for (; q--; ) {
		string s;
		cin >> s;
		if (s[0] == 'G') {
			printf ("%d\n", distance(t.t[1].p[0], t.t[1].p[1]));
		} else {
			int x = Read();
			t.Modify(1, b[x]);
		}
	}
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2022-11-15 07:28:12