Educational Codeforces Round 94 Editorial F

复杂度的问题(题解在下面)

x <= 20, 我们可以, 暴力把所有的 x-prime 跑出来, 这是跑出 x = 1 ~ 20 并插入ac自动机 每次 大约 所需要计算次数

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;

const int N = 3e5 + 5;

int n, m, _, k;
int a[21];
long long ans = 0;

bool check(int k) {
    rep (i, 1, n) {
        int cur = 0;
        rep (j, i, n) {
            ans += 3;
            cur += a[j];
            if (cur != n && n % cur == 0) return 0;
        }
    }
    return 1;
}

void dfs(int x, int y) {
    if (!y) {
        if (check(x - 1)) ans += (x << 1);
        return;
    }
    rep (i, 1, min(y, 9)) ans += 4, a[x] = i, dfs(x + 1, y - i);
}

int main() {
    IOS; 
    rep (i, 1, 20) ans = 0, dfs(1, i), cout << ans << '
';
    return 0;
}

1~20 所需的计算数量

8
22
52
116
252
540
1148
2428
5116
10740
22492
47000
98020
204060
424124
880188
1824124
3775484
7804924
16116742

不会超过2e8的数量级, 也就是1s可以跑出来, 题目给的是2s, 剩下的时间可以用来解决本题

题解

暴力跑出所有符合 x-prime 的字符串加入ac自动机

f[i][j] 表示字符串 第i个字符处在 自动机第 j 个节点,, 的最小花费

只要转移的时候不走到自动机的字符串结尾节点, 就不会有 x-prime, 哪怕你在节点 0

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;

const int N = 5e3 + 5;

int n, m, _, k;
int a[21], x, len = 1;
int f[2][N];
char s[1005];

namespace AC {
	const int C = 1;
	const int M = 9;

	struct ACstruct {
		int trie[N][M], fail[N];
		bool ended[N];
		int q[N], tot;

		void insert(int k) {
			int p = 0;
			rep(i, 1, k) {
				int ch = a[i] - C;
				if (!trie[p][ch]) trie[p][ch] = ++tot;
				p = trie[p][ch];
			}
			ended[p] = 1;
		}

		void build() {
			int head = 0, tail = -1;
			rep(i, 0, M - 1)
				if (trie[0][i])
					q[++tail] = trie[0][i];
			while (head <= tail) {
				int p = q[head++];
				rep(i, 0, M - 1)
					if (trie[p][i])
						fail[trie[p][i]] = trie[fail[p]][i],
						q[++tail] = trie[p][i];
					else trie[p][i] = trie[fail[p]][i];
			}
		}
	}ac;
}

bool check(int k) {
	rep(i, 1, k) {
		int cur = 0;
		rep(j, i, k) {
			cur += a[j];
			if (cur != x && x % cur == 0) return 0;
		}
	}
	return 1;
}

void dfs(int x, int y) {
	if (!y) {
		if (check(x - 1)) AC::ac.insert(x - 1);
		return;
	}
	rep(i, 1, min(y, 9)) a[x] = i, dfs(x + 1, y - i);
}

int main() {
	IOS; cin >> s + 1 >> x;
	memset(f[0], 0x3f, sizeof f[0]);
	dfs(1, x); AC::ac.build();
    f[0][0] = 0;
	for (int& i = len; s[i]; ++i) {
		int a = i & 1, b = a ^ 1, ch = s[i] - '1';
		memset(f[a], 0x3f, sizeof f[a]);
		rep(j, 0, AC::ac.tot)
			if (f[b][j] != 0x3f3f3f3f) {
				f[a][j] = min(f[a][j], f[b][j] + 1);
				int v = AC::ac.trie[j][ch];
				if (!AC::ac.ended[v]) f[a][v] = min(f[a][v], f[b][j]);
			}
	}--len;
	int ans = len;
	rep(i, 0, AC::ac.tot) ans = min(ans, f[len & 1][i]);
	cout << ans;
	return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/13629226.html