冲刺省选3月4日第二十五场

冲刺省选3月4日第二十五场

前缀

给定字符串 \(s\),求它的所有非空前缀在 \(s\) 中出现的次数之和。

\(|s|\le 10^7\)

看数据范围,看着就很线性。

考虑直接动态规划,设 \(f_i\) 表示以 \(s[j:i]\) 这类串能计入答案的个数。

那么考虑,这个 \([j:i]\) 的范围,这时候如果你用一个 \(nxt_i\)(KMP算法里的),来表示,不难发现 \(f_i=f_{nxt_i}+1\)。+1代表 \([1:i]\) 的贡献。

然后答案就是 \(\sum_{i=1}^N f_i\)

#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::swap;
using std::cerr;
using std::function;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {
		eng.seed(Seed);
		return;
	}
	int rnd(int l = 1, int r = 1000000000) {
		return uniform_int_distribution<int> (l, r)(eng);
	}
}
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template <typename T>
inline T read() {
	T x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) {
		f = ch == '-';
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f ? -x : x;
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1e7 + 10, MOD = 998244353, inv2 = (MOD + 1) / 2;
auto Ksm = [] (int x, int y) -> int {
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) {
		if (y & 1) {
			ret = (long long) ret * x % MOD;
		} 
	}
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) {
		return x - MOD;
	}
	else if (x < 0) {
		return x + MOD;
	}
	else {
		return x;
	}
};
inline int ls(int k) {
	return k << 1;
}
inline int rs(int k) {
	return k << 1 | 1;
}
int N, nxt[MAXN], dp[MAXN];
long long ans;
char s[MAXN];
int main() {
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	freopen("pre.in", "r", stdin);
	freopen("pre.out", "w", stdout);
	qwq::init(20050112);
	scanf("%s", s + 1);
	N = strlen(s + 1);
	nxt[0] = -1;
	for (int i = 1, j; i <= N; ++i) {
		j = nxt[i - 1];
		while (j != -1 && s[j + 1] != s[i]) {
			j = nxt[j];
		}
		nxt[i] = j + 1;
	}
	for (int i = 1; i <= N; ++i) {
		ans += (dp[i] = dp[nxt[i]] + 1);
	}
	cout << ans << '\n';
	return (0-0);
}

斐波那契

有一个长度为 \(n\) 的正整数序列 \(a\)(下标从1开始),共有 \(m\) 次操作,每次操作是如下 2 种操作中的一个:

1 l r x:将下标区间 \([l,r]\) 内的所有 \(a_i\) 都加上 \(x\)

2 l r:查询下标区间 \([l,r]\) 内所有 \(a_i\) 的斐波那契数列的第 \(a_i\) 项的和,也就是 \(f(a_l) + f(a_{l+1}) + … + f(a_r)\)

其中,\(f(1) = f(2) = 1\)\(f(i) = f(i-1) + f(i-2)\)

你就考虑。。 \(f_n=\frac{1}{\sqrt 5} \left(\left(\frac{1+\sqrt 5}{2}\right)^n-\left(\frac{1-\sqrt 5}{2}\right)^n\right)\)

然后,求出来 5 对于模数下面的二次剩余,之后相当于是,对于两个项单独维护,之后就是区间的一个乘法罢了。

时间复杂度 \(O(n\log n)\)

#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::swap;
using std::cerr;
using std::function;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {
		eng.seed(Seed);
		return;
	}
	int rnd(int l = 1, int r = 1000000000) {
		return uniform_int_distribution<int> (l, r)(eng);
	}
}
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template <typename T>
inline T read() {
	T x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) {
		f = ch == '-';
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f ? -x : x;
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 1e5 + 10, MOD = 1004535809, inv2 = (MOD + 1) / 2, fiv = 200717101;
auto Ksm = [] (int x, int y) -> int {
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) {
		if (y & 1) {
			ret = (long long) ret * x % MOD;
		} 
	}
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) {
		return x - MOD;
	}
	else if (x < 0) {
		return x + MOD;
	}
	else {
		return x;
	}
};
const int ifiv = Ksm(fiv, MOD - 2);
inline int ls(int k) {
	return k << 1;
}
inline int rs(int k) {
	return k << 1 | 1;
}
int w;
typedef std::pair<int, int> complex;
complex operator + (complex &x, complex &y) {
	return std::make_pair((x.first + y.first) % MOD, (x.second + y.second) % MOD);
}
complex operator - (complex &x, complex &y) {
	return std::make_pair((x.first - y.first + MOD) % MOD, (x.second - y.second + MOD) % MOD);
}
complex operator * (complex &x, complex &y) {
	return std::make_pair(((long long) x.first * y.first + (long long) w * x.second % MOD * y.second) % MOD, ((long long) x.first * y.second + (long long) y.first * x.second) % MOD);
}
complex ksm(complex x, int y) {
	complex res(1, 0);
	for (; y; y /= 2, x = x * x) {
		if (y & 1) {
			res = res * x;
		}
	}
	return res;
}
bool check(int x) {
	return Ksm(x, (MOD - 1) / 2) == 1;
}
int Sqrt(int x) {
	if (!x) {
		return x;
	}
	else {
		int a = qwq::rnd() % MOD;
		while (check(((long long) a * a + MOD - x) % MOD)) {
			a = qwq::rnd() % MOD;
		}
		w = ((long long) a * a + MOD - x) % MOD;
		complex b(a, 1);
		int ans1(ksm(b, (MOD + 1) / 2).first);
		return min(ans1, MOD - ans1);
	}
}
int N, Q, A[MAXN];
struct SGT {
	int v, sum[MAXN * 4], tag[MAXN * 4];
	SGT(int V) {
		v = V;
	}
	void up(int k) {
		sum[k] = Mod(sum[ls(k)] + sum[rs(k)]);
		return;
	}
	void puttag(int k, int x) {
		tag[k] = (tag[k] + x);
		if (tag[k] >= MOD - 1) {
			tag[k] -= MOD - 1;
		}
		sum[k] = (long long) sum[k] * Ksm(v, x) % MOD;
		return;
	}
	void down(int k) {
		if (tag[k]) {
			puttag(ls(k), tag[k]);
			puttag(rs(k), tag[k]);
			tag[k] = 0;
		}
		return;
	}
	void build(int *val) {
		function<void(int, int, int)> dfs = [&] (int nw, int l, int r) -> void {
			if (l == r) {
				sum[nw] = Ksm(v, A[l]);
				return;
			}
			int mid = (l + r) / 2;
			dfs(ls(nw), l, mid);
			dfs(rs(nw), mid + 1, r);
			up(nw);
		};
		dfs(1, 1, N);
		return;
	}
	void mfy(int ql, int qr, int qx) {
		function<void(int, int, int)> dfs = [&] (int nw, int l, int r) -> void {
			if (ql <= l && r <= qr) {
				return puttag(nw, qx);
			}
			down(nw);
			int mid = (l + r) / 2;
			if (ql <= mid) {
				dfs(ls(nw), l, mid);
			}
			if (mid < qr) {
				dfs(rs(nw), mid + 1, r);
			}
			up(nw);
		};
		return dfs(1, 1, N);
	}
	int qry(int ql, int qr) {
		function<int(int, int, int)> dfs = [&] (int nw, int l, int r) -> int {
			if (ql <= l && r <= qr) {
				return sum[nw];
			}
			down(nw);
			int mid = (l + r) / 2, ret = 0;
			if (ql <= mid) {
				ret = dfs(ls(nw), l, mid);
			}
			if (mid < qr) {
				ret = Mod(ret + dfs(rs(nw), mid + 1, r));
			}
			return ret;
		};
		return dfs(1, 1, N);
	}
} T1((fiv + 1) / 2), T2((1LL - fiv + MOD) * inv2 % MOD);
int main() {
	freopen("fib.in", "r", stdin);
	freopen("fib.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	cout << std::fixed << std::setprecision(8);
	cin.tie(0);
	cout.tie(0);
	qwq::init(20050112);
	// cout << Sqrt(5);
	// cout << (long long) fiv * fiv % MOD;
	cin >> N >> Q;
	for (int i = 1; i <= N; ++i) {
		cin >> A[i];
	}
	T1.build(A);
	T2.build(A);
	for (int opt, l, r, x; Q--; ) {
		cin >> opt >> l >> r;
		if (opt == 1) {
			cin >> x;
			T1.mfy(l, r, x);
			T2.mfy(l, r, x);
		}
		else {
			int res = (long long) ifiv * Mod(T1.qry(l, r) - T2.qry(l, r)) % MOD;
			cout << res << '\n';
		}
	}
	return (0-0);
}

过路费

某国共有 \(n\) 座城市,有 \(m\) 条高速公路连接这些城市,每条高速公路只能单向通行。

第i条高速公路的起点城市是 \(u_i\),终点城市是 \(v_i\),经过一次需要 \(w_i\) 的费用。

节假日到了,国家决定对高速公路通行费进行减免,政策如下:

如果一条路线经过的高速公路不超过 \(k\) 条,将按照原价收取费用。

如果一条路线经过的高速公路超过 \(k\) 条,将只收取其中费用最高的 \(k\) 条高速公路的费用。

求:从城市 \(s\) 到城市 \(t\) 的最小花费。

考虑使用类似于忘情水二分的技巧,考虑对于每个权值做一次 dijkstra,设当前的权值为 \(v\),那么每条边的权值就是 \(\max(0,x-v)\)

这样跑出来的答案,那么答案就是 \(\min dis_t+v\times k\)

就是说,你钦定一个权值是 \(k\) 小的。

然后每做一次复杂度是 \(O(m\log n)\) 的,然后总复杂度就是 \(O(m^2\log n)\) 的了。

#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::swap;
using std::cerr;
using std::function;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {
		eng.seed(Seed);
		return;
	}
	int rnd(int l = 1, int r = 1000000000) {
		return uniform_int_distribution<int> (l, r)(eng);
	}
}
template <typename T>
inline T min(const T &x, const T &y) {
	return x < y ? x : y;
}
template<typename T>
inline T max(const T &x, const T &y) {
	return x > y ? x : y;
}
template <typename T>
inline T read() {
	T x = 0;
	bool f = 0;
	char ch = getchar();
	while (!isdigit(ch)) {
		f = ch == '-';
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return f ? -x : x;
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 4000, MOD = 998244353, inv2 = (MOD + 1) / 2;
auto Ksm = [] (int x, int y) -> int {
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) {
		if (y & 1) {
			ret = (long long) ret * x % MOD;
		} 
	}
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) {
		return x - MOD;
	}
	else if (x < 0) {
		return x + MOD;
	}
	else {
		return x;
	}
};
inline int ls(int k) {
	return k << 1;
}
inline int rs(int k) {
	return k << 1 | 1;
}
vector<pair<int, int>> E[MAXN];
int k,m,n,s,t, vis[MAXN];
long long ans = 0x3f3f3f3f3f3f3f3f, dis[MAXN];
void dijkstra(int k) {
	memset(dis, 63, sizeof dis);
	dis[s] = 0;
	std::priority_queue<pair<long long, int>, vector<pair<long long, int>>, std::greater<pair<long long, int>>> Q;
	Q.push({0, s});
	memset(vis, 0, sizeof vis);
	while (Q.size()) {
		auto tp = Q.top().second;
		Q.pop();
		if (vis[tp]) {
			continue;
		}
		vis[tp] = 1;
		for (auto &j: E[tp]) {
			int w = max(0, j.second - k);
			if (dis[tp] + w < dis[j.first]) {
				Q.push({dis[j.first] = dis[tp] + w, j.first});
			}
		}
	}
	return;
}
int main() {
	freopen("fee.in", "r", stdin);
	freopen("fee.out", "w", stdout);
	std::ios::sync_with_stdio(0);
	cout << std::fixed << std::setprecision(8);
	cin.tie(0);
	cout.tie(0);
	qwq::init(20050112);
	cin >> n >> m >> k >> s >> t;
	for (int i = 1, x, y, z; i <= m; ++i) {
		cin >> x >> y >> z;
		E[x].push_back(make_pair(y, z));
	}
	for (int i = 1; i <= n; ++i) {
		for (auto &j: E[i]) {
			dijkstra(j.second);
			ans = min(ans, dis[t] + (long long) k * j.second);
		}
	}
	cout << ans << '\n';
	return (0-0);
}
posted @ 2022-03-04 19:19  siriehn_nx  阅读(70)  评论(0编辑  收藏  举报