考试杂写1
由于没有写完整题解的时间以及那个毅力
我选择杂写
并非按照时间顺序,只能说是乱jb写
题面挂了链接,不知道的你也进不去
1.10/02多校 T1 二分图排列
个人认为难度大概是T3,赛时断断续续搞了好久(其实全是扯淡)
因为每个逆序对都要连边,所以我会和所有我前面的比我大的连边
那么如果取反,则我直接和在原序列中比我小的连边
又因为要求二分图,所以不能有奇环,所以不能有长度大于2的下降子序列(赛时就到这了)
于是可以得出结论:
构造之后的序列只有能够分成两个上升子序列,才可以构造出合法方案
开D
为了后面方便贪心的构造。我们选择倒序D
定义
所以转移到
只要这四个值大于我的
全部初始化成极小值,如果
考虑在有解情况下贪心构造
维护两个值
因为字典序最小,能负就负,不能负就正,配合
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define M 505
#define ll long long
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define dwn(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define inf 2147483647
using namespace std;
int wrt[20], TP;
inline int Min(int a, int b) { return a < b ? a : b; } inline int Max(int a, int b) { return a > b ? a : b; }
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)) {if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, bool op) {TP = 0;if (x < 0) putchar('-'), x = -x;while(x >= 10) wrt[++TP] = x % 10, x /= 10; wrt[++TP] = x;while(TP) putchar(wrt[TP--] | 48);if (op) putchar('\n'); else putchar(' ');}
inline int qbow(int a, int b, int p) {int res = 1;while(b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;}
int n, a[M], f[M][2];
WWW main() {
int T = read();
while(T--) {
n = read(); bool op = true;
rep(i, 1, n) a[i] = read(), f[i][0] = f[i][1] = -inf;
f[n + 1][0] = f[n + 1][1] = a[n + 1] = inf;
dwn(i, n, 1) {
rep(j, 0, 1) {
int x = j ? -a[i] : a[i];
if (a[i + 1] > x) f[i][j] = Max(f[i][j], f[i + 1][0]);
if (-a[i + 1] > x) f[i][j] = Max(f[i][j], f[i + 1][1]);
if (f[i + 1][0] > x) f[i][j] = Max(f[i][j], a[i + 1]);
if (f[i + 1][1] > x) f[i][j] = Max(f[i][j], -a[i + 1]);
}
if (f[i][0] == -inf and f[i][1] == -inf) { op = false; break; }
}
if (!op) { puts("NO"); continue; }
else puts("YES");
int now1 = -inf, now2 = -inf;
rep(i, 1, n) {
if (-a[i] > now1) now1 = -a[i], print(-a[i], 0);
else if (-a[i] > now2 && -a[i] < f[i][1]) now2 = -a[i], print(-a[i], 0);
else now1 = a[i], print(a[i], 0);
if (now1 < now2) swap(now1, now2);
}
putchar('\n');
}
return 0;
}
2. 10/02多校 T2 最短路问题 V3
这个题不难,放在T1比较合适(没切的我是彩笔)
观察数据范围
这个很奇特,令人不由自主的就觉得有问题
那么我们由此入手
对原图跑一棵生成树出来,顺便剖掉
那么在树上询问两点距离直接
但是由于非树边的存在导致最短路可能更短
那么我们对每条非树边的两点进行一个
因为非树边很少,最多
每个询问的时候再遍历每个特殊点和
写个题的原因就是好好看数据范围,知道有不对劲的东西就尽力深挖
正解大概率相关
3. 10/01 国庆のsurprise T2 Su_Zipei is always here
呃呃
无事发生
一道根号分治,似乎暑假的时候有一道,不过忘掉了
为了方便描述,我们定义出现次数多于
而少于
可以发现,重要元素的数量一定少于
于是我们针对两个少于
在时间和空间上达到
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define M 100005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define dwn(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
using namespace std;
int wrt[20], TP;
inline int Min(int a, int b) { return a < b ? a : b; } inline int Max(int a, int b) { return a > b? a : b; }
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)) {if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, bool op) {TP = 0;if (x < 0) x = -x, putchar('-');while(x >= 10) wrt[++TP] = x % 10, x /= 10;wrt[++TP] = x; while(TP) putchar(wrt[TP--] | 48); if (op) putchar('\n'); else putchar(' ');}
int n, m, q, opt, a[M], st[M], ed[M], bl[M];
int pos[320][M], bh[M], num;//第i种重要元素在前j个位置有多少个
int sum[320][M];//前i块元素为j的数量
int tot[320][320][320];//[i, j]块内出现大于等于k次的元素数量
int cnt[M];//桶
void fk() {
rep(i, 1, q) st[i] = ed[i - 1] + 1, ed[i] = n / q * i;
if (ed[q] != n) st[q + 1] = ed[q] + 1, ed[++q] = n;
rep(i, 1, q) rep(j, st[i], ed[i]) bl[j] = i;
rep(i, 1, n) cnt[a[i]]++;
rep(i, 1, n) if (cnt[i] > q) bh[i] = ++num;
rep(i, 1, n) cnt[a[i]] = 0;
rep(i, 1, n) if (bh[a[i]]) pos[bh[a[i]]][i]++;
rep(i, 1, num) rep(j, 1, n) pos[i][j] += pos[i][j - 1];//对重要元素的处理,O(nsqrtn)
rep(i, 1, q) {
rep(j, st[i], ed[i]) if (!bh[a[j]]) sum[i][a[j]]++;
rep(j, 1, n) sum[i][j] += sum[i - 1][j];
}
rep(i, 1, q) {
rep(j, i, q) {
rep(k, 1, q) tot[i][j][k] = tot[i][j - 1][k];
rep(k, st[j], ed[j]) {
if (!bh[a[k]]) {
tot[i][j][cnt[a[k]]]--;
tot[i][j][++cnt[a[k]]]++;
}
}
}
rep(k, 1, n) cnt[k] = 0;
}
rep(i, 1, q) rep(j, i, q) dwn(k, q, 1) tot[i][j][k] += tot[i][j][k + 1];//对普遍元素的处理,O(nsqrtn)
}
inline int query(int l, int r, int k) {
int res = 0;
if (bl[r] - bl[l] < 2) {
rep(i, l, r) {
cnt[a[i]]++;
if (cnt[a[i]] == k) res++;
}
rep(i, l, r) cnt[a[i]] = 0;
}else {
if (k <= q) res = tot[bl[l] + 1][bl[r] - 1][k];//小于根号直接先统计一把
rep(i, l, ed[bl[l]]) {
if (!bh[a[i]]) {
cnt[a[i]]++;
if (cnt[a[i]] + sum[bl[r] - 1][a[i]] - sum[bl[l]][a[i]] == k) res++;
}
}
rep(i, st[bl[r]], r) {
if (!bh[a[i]]) {
cnt[a[i]]++;
if (cnt[a[i]] + sum[bl[r] - 1][a[i]] - sum[bl[l]][a[i]] == k) res++;
}
}
rep(i, l, ed[bl[l]]) cnt[a[i]] = 0; rep(i, st[bl[r]], r) cnt[a[i]] = 0;
rep(i, 1, num) if (pos[i][r] - pos[i][l - 1] >= k) res++;
}
return res;
}
WWW main() {
n = read(), m = read(), opt = read(); q = sqrt(n);
rep(i, 1, n) a[i] = read();
fk();
int ans = 0;
while(m--) {
int f = ans * opt - 1;
int l = (read() + f) % n + 1, r = (read() + f) % n + 1, k = (read() + f) % n + 1;
if(l > r) swap(l, r);
ans = query(l, r, k);
print(ans, 1);
}
return 0;
}
4. 9/30 CSP-S模拟15 T3 追逐
当我们固定一个起点后,把起点作为整个树的根,那么这时每个节点选不选的价值就是它所有儿子的铁球数量加和。
首先,树形dp还是比较好想且显然的
定义
考虑当前节点则转移为
而
这样每个点作为树根跑一边
(见到
所以我们考虑换根
在原
然后就有了
只是转移路径变了,定义不变
通俗点的理解就是你把
看图
然后变成这样
所以你相当就是用
所以在第一次统计
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define M 100005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
#define int long long
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define dwn(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
using namespace std;
int wrt[20], TP;
inline ll Max(ll a, ll b) { return a > b ? a : b; }
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)) {if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, bool op) {TP = 0;if (x < 0) x = -x, putchar('-');while(x >= 10) wrt[++TP] = x % 10, x /= 10;wrt[++TP] = x; while(TP) putchar(wrt[TP--] | 48); if (op) putchar('\n'); else putchar(' ');}
int n, m, a[M]; ll sum[M], ans;
struct egde { int v, next; }e[M << 1];
int head[M], tot = 1;
void add(int u, int v) { e[tot].v = v, e[tot].next = head[u], head[u] = tot++; }
ll f[M][101][2], g[M][101][2];//原dp数组和换根dp数组
int mx[M][101][2], mn[M][101][2];//贡献最大值和次大值所在的节点
inline void updata(int rt, int v, int j, int op) {//记录最大值和次大值
if (f[mx[rt][j][op]][j][op] <= f[v][j][op]) mn[rt][j][op] = mx[rt][j][op], mx[rt][j][op] = v;
else if (f[mn[rt][j][op]][j][op] < f[v][j][op]) mn[rt][j][op] = v;
}
inline int query(int rt, int v, int j, int op) {
if (mx[rt][j][op] == v) return mn[rt][j][op];
return mx[rt][j][op];
}
void dfs1(int x, int fa) {
sum[x] = 0;
for (int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
if (v == fa) continue;
dfs1(v, x); sum[x] += a[v];
}
rep(j, 0, m) {//枚举数量
for (int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
if (v == fa) continue;
updata(x, v, j, 0), updata(x, v, j, 1);
f[x][j][0] = Max(f[x][j][0], Max(f[v][j][0], f[v][j][1]));
if (j) f[x][j][1] = Max(f[x][j][1], Max(f[v][j - 1][0], f[v][j - 1][1]) + sum[x]);
}
}
}
void dfs2(int x, int fa) {
ll mx0 = 0, mx1 = 0;
rep(j, 0, m) {//换根,考虑我如果以当前节点为根,那么也要考虑父亲一方的贡献
mx0 = Max(Max(g[fa][j][0], g[fa][j][1]), Max(f[mx[x][j][0]][j][0], f[mx[x][j][1]][j][1]));//当前节点不选
if (j) mx1 = Max(Max(g[fa][j - 1][0], g[fa][j - 1][1]), Max(f[mx[x][j - 1][0]][j - 1][0], f[mx[x][j - 1][1]][j - 1][1])) + sum[x] + a[fa];//当前节点选
ans = Max(ans, Max(mx0, mx1));
}
for (int i = head[x]; i; i = e[i].next) {
int v = e[i].v;
if (v == fa) continue;
rep(j, 0, m) {
mx0 = query(x, v, j, 0), mx1 = query(x, v, j, 1);
g[x][j][0] = Max(Max(g[fa][j][0], g[fa][j][1]), Max(f[mx0][j][0], f[mx1][j][1]));
if (j) {
mx0 = query(x, v, j - 1, 0), mx1 = query(x, v, j - 1, 1);
g[x][j][1] = Max(Max(g[fa][j - 1][0], g[fa][j - 1][1]), Max(f[mx0][j - 1][0], f[mx1][j - 1][1])) + sum[x] + a[fa] - a[v];
}
}
dfs2(v, x);
}
}
WWW main() {
n = read(), m = read();
rep(i, 1, n) a[i] = read();
rep(i, 2, n) { int u = read(), v = read(); add(u, v), add(v, u); }
dfs1(1, 0); dfs2(1, 0);
print(ans, 0);
return 0;
}
5. 9/29 CSP-S模拟14 T2 尽梨了
一个一眼看上去就很奇怪且不可做题
结论是一道组合数学,考虑怎么算贡献
因为一个
并且属于只要有一个合法即可,所以我们考虑固定一位来算另一位的贡献
考虑枚举我有几列放
对于一行来讲,1的个数是一定的且可以预处理的
那么设
那么分成了三种情况:
对于
对于
那么显然只有
那么考虑是否有
如果存在,那么就要满足每行状态一样,对答案的贡献就是
如果不存在,设
这个组合数的意义就是我目前要求放
然后用
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bitset>
#include <vector>
#define M 5005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
#define int long long
#define mod 998244353
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); i++)
#define dwn(i, a, b) for (int (i) = (a); (i) >= (b); i--)
using namespace std;
int wrt[20], TP;
inline int Max(int a, int b) { return a > b ? a : b; } inline int Min(int a, int b) { return a < b ? a : b; }
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)){if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, int op) {TP = 0;if (x < 0) x = -x, putchar('-');while(x >= 10) wrt[++TP] = x % 10, x /= 10; wrt[++TP] = x;while(TP) putchar(wrt[TP--] | 48); if (op) putchar('\n'); else putchar(' ');}
inline int qbow(int a, int b, int p) {ll res = 1;while(b) {if (b & 1) res = res * a % p;a = a * a % p;b >>= 1;}return res;}
int n, res[M]; char s[M]; ll jc[M], inv[M], ans;
bitset<M> bt[M], b1[M], b2[M];
vector<int> v[M];
inline int C(int n, int m) {
if (n < m || n < 0 || m < 0) return 0;
return jc[n] * inv[n - m] % mod * inv[m] % mod;
}
WWW main() {
n = read(); jc[0] = inv[0] = 1;
rep(i, 1, n) jc[i] = jc[i - 1] * i % mod;
inv[n] = qbow(jc[n], mod - 2, mod);
dwn(i, n - 1, 1) inv[i] = inv[i + 1] * (i + 1) % mod;
rep(i, 1, n) {
scanf("%s", s + 1);
rep(j, 1, n) {
bt[i][j] = s[j] == '1' ? 1 : 0;
if (bt[i][j]) res[i]++;
}
v[res[i]].push_back(i);
}
rep(i, 1, n) {
b1[i] = b1[i - 1];
for (auto j : v[i]) b1[i] |= bt[j];
}
rep(i, 1, n) b2[n + 1][i] = 1;
dwn(i, n, 1) {
b2[i] = b2[i + 1];
for (auto j : v[i]) b2[i] &= bt[j];
}
rep(s, 0, n) {
if ((b1[s] | b2[s]) == b2[s]) {//b2选0的位置依旧是0代表没有冲突
if (v[s].size()) { (ans += qbow(2, v[s].size(), mod)) %= mod; continue; }
int k1 = b1[s].count(), k2 = b2[s].count();
(ans += C(k2 - k1, s - k1)) %= mod;
}
}
print(ans, 0);
return 0;
}
6. 9/22 CSP-S模拟9 T1 最长上升子序列
一道贪心的构造
考虑已经给出来的这个上升序列不变,我们往里面塞数
对于原序列
两个数中间的数不能放在两个数中间
并且要求了字典序最小,那么我们考虑贪心的进行构造
第一个数显然不能放比给出的第一个数更小的数,又要求字典序最小,那第一个数就放给出的第一个数
考虑第二个数要怎么放,如果放原序列第二个数肯定没问题,但为了字典序最小,我们决定放一个更小的数,越小越好,所以我们拿出一个还没有放过的最小且比上一个数要小的数放在这个位置,这样这个数不会被夹在两个数中间就不会有贡献
下一个数就再放我原序列的数即可
但是如果没有小的你就不放,因为你放了还不如不放(这片题解怎么这么多屁话)
因为你放了字典序肯定更大,所以就不放
最后所有剩下的数倒序甩到后面就行
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define M 200005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
using namespace std;
inline int Max(int a, int b) {return a > b ? a : b;}
inline int read() {
int x = 0;
bool f = false;
char c = getchar();
while(!isdigit(c)) {
if (c == '-') f = true;
c = getchar();
}
do {
x = (x << 1) + (x << 3) + (c ^ 48);
}while(isdigit(c = getchar()));
if (f) return -x;
return x;
}
int n, k, a[M], v[M];
WWW main() {
n = read(); k = read();
for (int i = 1; i <= k; i++) a[i] = read(), v[a[i]] = i;
int j = 1;
for (int i = 1; i < k; i++) {
printf("%d ", a[i]);
while(v[j]) j++;
if (j < a[i]) {
printf("%d ", j);
v[j] = n + 1;
}
}
for (int i = n; !v[i]; i--) printf("%d ", i), v[i] = n + 1;
printf("%d ", a[k]);
for (int i = n; i >= 1; i--) if (!v[i]) printf("%d ", i);
return 0;
}
7. 9/22 CSP-S模拟9 T2 独特序列
一道D,求所有不重复子序列的方案
定义
那么转移就是
意义很好理解,
用链表和树状数组维护即可
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define M 200005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
#define mod 998244353
using namespace std;
inline int Max(int a, int b) {return a > b ? a : b;}
inline int read() {
int x = 0;
bool f = false;
char c = getchar();
while(!isdigit(c)) {
if (c == '-') f = true;
c = getchar();
}
do {
x = (x << 1) + (x << 3) + (c ^ 48);
}while(isdigit(c = getchar()));
if (f) return -x;
return x;
}
int n, a[M], lst[M], nxt[M], pre[M];//lst维护了最后一个位置,pre,nxt是指向了上下一个本元素的位置
ll c[M], f[M], ans;
#define low_bit (x & -x)
void updata(int x, ll val) { while(x <= n) (c[x] += val) %= mod, x += low_bit; }
ll getsum(int x) {
if (x <= 0) return 0;
ll res = 0;
while(x) (res += c[x]) %= mod, x -= low_bit;
return res;
}
WWW main() {
n = read();
for (int i = 1; i <= n; i++) {
a[i] = read();
if (lst[a[i]]) nxt[lst[a[i]]] = i, pre[i] = lst[a[i]];
lst[a[i]] = i;
}
updata(1, 1);
f[1] = 1;
if (!nxt[1]) ans++;
for (int i = 2; i <= n; i++) {
f[i] = (getsum(i - 1) - getsum(pre[i] - 1) + mod) % mod;
if (pre[i]) updata(pre[i], -f[pre[i]]); else f[i]++;
if (!nxt[i]) (ans += f[i]) %= mod;//这个元素结尾的所有贡献
updata(i, f[i]);
}
printf("%lld\n", ans);
return 0;
}
8. 9/22 CSP-S模拟9 T3 最大GCD
一个还算有意思的题
如果
那我们考虑如果不行捏,那不行的话,就很烦
我们先想一个暴力,暴力枚举
那么只要满足
此时你觉得数论分块可做,但是交上去T掉了
考虑一点数学知识,现在的复杂度凝固在了
即在
那么我们可以对
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define M 300005
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define ll long long
using namespace std;
inline ll read() {
ll x = 0;
bool f = false;
char c = getchar();
while(!isdigit(c)) {
if (c == '-') f = true;
c = getchar();
}
do {
x = (x << 1) + (x << 3) + (c ^ 48);
}while(isdigit(c = getchar()));
if (f) return -x;
return x;
}
int n;
ll sum, avr, k, a[M];
WWW main() {
n = read(), sum = k = read();
for (int i = 1; i <= n; i++) a[i] = read(), sum += a[i];
avr = sum / n;
cerr << avr;
sort(a + 1, a + 1 + n);
for (ll s = avr; s >= 2; s--) {
ll f = 0; bool op = true;
for (int i = 1; i <= n; i++) {
f += (ll)ceil(1.0 * a[i] / s) * s - a[i];
if (f > k) { op = false; break; }
}
if (op) { printf("%lld", s); return 0; }
}
printf("1");
return 0;
}
9.10/08多校 T2 天☆堂
先想暴力,把所有的子串取出来按照字典序赋一个值,于是我们得到一个
那么这个实在是太暴力了,虽然分并不少,但我们考虑优化
时间复杂度必须保证在
我们先考虑一些事情,如果我选中了一个
所以对于一个固定的
考虑另外一个事情,我对于一个
证明这个东西也不难,如果后面有一个位置
最后一个事情,我比较两个串的字典序比较的到底是什么
是两个字符串的LCP后的第一个字符
那么只要我们处理出任意两个串的
设
那么我们倒序枚举,转移就很显然了
那么状态数从
时间复杂度O(n^2)
结束
AC代码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define M 5005
#define ll long long
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define fin(x) freopen(#x ".in", "r", stdin)
#define rep(i, a, b) for (register int (i) = (a); (i) <= (b); (i)++)
#define dwn(i, a, b) for (register int (i) = (a); (i) >= (b); (i)--)
using namespace std;
int wrt[20], TP;
inline int Max(int a, int b) { return a > b ? a : b; }
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)) {if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, bool op) {TP = 0;if (x < 0) x = -x, putchar('-');while(x >= 10) wrt[++TP] = x % 10, x /= 10; putchar(x | 48);while(TP) putchar(wrt[TP--] | 48); if (op) putchar('\n'); else putchar(' ');}
int n, f[M], pos[M][M]; char s[M];
WWW main() {
int T = read();
while(T--) {
n = read();
scanf("%s", s + 1);
dwn(i, n, 1) dwn(j, n, i) {
pos[i][j] = 0;
if (s[i] == s[j]) pos[i][j] = pos[i + 1][j + 1] + 1;
}
int ans = 0;
rep(i, 1, n) {
f[i] = n - i + 1;
rep(j, 1, i - 1) {
int zi = i + pos[j][i], zj = j + pos[j][i];
if (zi <= n and s[zi] > s[zj]) f[i] = Max(f[i], f[j] + n - zi + 1);
}
ans = Max(ans, f[i]);
}
print(ans, 1);
}
return 0;
}
10. 10/06多校 T4 D
期望D
评价是不想写高斯,所以我们选择递推
设
很好理解,就是有
而
考虑配合
对于第
如果不同,此时如果
如果相同,那么失配的话我就接不到这个位置,所以不能直接转移
但是我既然相同,那么我正好接到我
但是实际处理为了第二个式子我们好转移,所以在第一个式子里我们不加那个
结束
AC代码
#define abhwolxq bailan
#define WWW signed
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define M 1000005
#define ll long long
#define int long long
#define mod 1000000007
#define fre(x) freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
#define rep(i, a, b) for(int (i) = (a); (i) <= (b); (i)++)
#define dwn(i, a, b) for(int (i) = (a); (i) >= (b); (i)--)
using namespace std;
int wrt[20], TP;
inline int read() {int x = 0;bool f = false;char c = getchar();while(!isdigit(c)) {if (c == '-') f = true;c = getchar();}do {x = (x << 1) + (x << 3) + (c ^ 48);}while(isdigit(c = getchar()));if (f) return -x;return x;}
inline void print(int x, bool op) {TP = 0;if (x < 0) putchar('-'), x = -x;while(x >= 10) wrt[++TP] = x % 10, x /= 10;putchar(x | 48);while(TP) putchar(wrt[TP--] | 48); if (op) putchar('\n'); else putchar(' ');}
inline int qbow(int a, int b, int p) { int res = 1; while(b) { if (b & 1) res = res * a % p; a = a * a % p; b >>= 1;} return res; }
int n, nxt[M], f[M], v[M]; char c[M];
WWW main() {
scanf("%s", c + 1); n = strlen(c + 1);
int j = 0;
rep(i, 2, n) {
while(j && c[j + 1] != c[i]) j = nxt[j];
if (c[j + 1] == c[i]) j++;
nxt[i] = j;
if (i != n) {
if (c[i + 1] != c[j + 1]) v[i] = j;
else v[i] = v[j];
}
}
int inv = qbow(2, mod - 2, mod);
rep(i, 1, n) {
int len = 0;
if (c[v[i - 1] + 1] != c[i]) len = v[i - 1] + 1;
f[i] = ((f[i - 1] * 2 - f[len] - 2) % mod + mod) % mod;
}
print(mod - f[n], 0);
return 0;
}
1313
(别问我什么含义,我也不知道)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通