冲刺省选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);
}