2023.7.30 DAY7解题报告
2023.7.30 DAY7解题报告
T1
暴力:直接模拟。
我们把每一个操作都模拟一下,我一开始用的 string,但是好像有长度上限,超了就炸了,改成了 char 数组,应该是慢了不少。
50pts;
#include <bits/stdc++.h>
#define int long long
#define N 10001000
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int n, m, k, L[N], R[N], maxn, C[N];
char s[N], ss[N];
signed main()
{
n = read(), m = read(), k = read();
for(int i = 1; i <= n; i ++)
cin >> s[i];
maxn = k;
for(int i = 1; i <= m; i ++)
{
L[i] = read(), R[i] = read(), C[i] = read();
maxn = max(maxn, R[i]);
}
if(n > 1000 || m > 1000 || k > 1000)
{
cout << s[1] << endl;
return 0;
}
int len = n;
while(len < maxn)
{
for(int i = len + 1; i <= len + n; i ++)
s[i] = s[i - len];
len += n;
}
n = len;
for(int i = 1; i <= m; i ++)
{
int cnt = 0;
int l = L[i], r = R[i], c = C[i];
for(int j = 1; j <= c; j ++) ss[++ cnt] = s[j];
for(int j = l; j <= r; j ++) ss[++ cnt] = s[j];
for(int j = c + 1; j <= n; j ++) ss[++ cnt] = s[j];
n = cnt;
for(int i = 1; i <= n; i ++) s[i] = ss[i];
}
cout << s[k] << endl;
return 0;
}
我们模拟一下,在这过程中最后怎么得到 \(k\) 的。
我们把询问一个一个倒回去,分下面三种情况:
-
当前的 \(k\) 小于 \(c_{i}\),那么挪过来的区间对他没有影响,我们可以不管。
-
当前的 \(k\) 在 \(c_{i}\sim c_{i} + len\) 之间,那么我们的 \(k\) 在之前转移过来的区间内,也就是 \(l_{i} - 1 + (k-c_{i})\)。
-
如果要是 \(k\) 在 \(c_{i} + len\) 之外,那么我们就把 \(k\) 往左挪 \(len\) 个单位就好。
code:
#include <bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
int n, m, k, l[N], r[N], c[N];
char s[N];
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
signed main()
{
n = read(), m = read(), k = read();
for(int i = 1; i <= n; i ++)
cin >> s[i];
for(int i = 1; i <= m; i ++)
l[i] = read(), r[i] = read(), c[i] = read();
for(int i = m; i >= 1; i --)
{
int len = r[i] - l[i] + 1;
if(c[i] + len < k) k -= len;
else if(c[i] < k && k <= c[i] + len) k = l[i] - 1 + (k - c[i]);
else if(k >= c[i]) k = k;
// cout << k << endl;
}
k %= n;
cout << s[k] << endl;
return 0;
}
T2
想到 KMP 了,但是没想到如何处理字符串。
一开始只想着怎么把 KMP 的过程改一下,但是正解是把原串处理一下跑 KMP。
考虑如何判断两个串相等?
记录每个字符和这个字符上次出现位置的距离,变成新的数组
两个字符串相等当且仅当新的数组相同
利用此性质做 KMP
#include <bits/stdc++.h>
#define int long long
#define N 1000100
using namespace std;
map<char, int> mp;
int n, a[N], nxt[N], ans;
char s[N];
signed main()
{
scanf("%s", s + 1);
n = strlen(s + 1);
for(int i = 1; i <= n; i ++)
{
a[i] = i - mp[s[i]];
mp[s[i]] = i;
}
int j = 0;
for(int i = 2; i <= n; i ++)
{
while(j && min(a[i], j + 1) != a[j + 1]) j = nxt[j];
if(min(a[i], j + 1) == a[j + 1]) j ++;
nxt[i] = j;
}
for(int i = 2; i <= n; i ++)
ans += nxt[i];
cout << ans << endl;
return 0;
}
T3
考虑一段区间可以开 \(k\) 次根号当且仅当区间乘起来以后每个质因子的幂次都是 \(k\) 的倍数。
维护一个串,第 \(i\) 为表示第 \(i\) 个质数的幂次模 \(k\) 的余数,当这个串全 \(0\) 时即为可以开 \(k\) 次根号。
考虑哈希维护这个串,用 map 存一下左端点,在右端点处询问即可。
注意用自然溢出而不是普通哈希。
#include <bits/stdc++.h>
#define int unsigned long long
#define M 10000000
#define N 10000100
#define base 131
using namespace std;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
int n, m, k, a[N], b[N], cnt[N], pm[N], now, ans, vis[N];
unordered_map<int, int> S;
signed main()
{
n = read(), m = read();
for(int i = 2; i <= M; i ++)
{
if(!vis[i]) pm[i] = ++ k, a[k] = i;
for(int j = 1; j <= k && i * a[j] <= M; j ++)
{
vis[i * a[j]] = 1, pm[i * a[j]] = j;
if (i % a[j] == 0) break;
}
}
b[0] = 1, ++ S[0];
for(int i = 1; i <= k; i ++) b[i] = b[i - 1] * base;
for(int i = 1; i <= n; i ++)
{
int x = read();
while(x != 1)
{
int y = pm[x], z = 0;
while(x % a[y] == 0) x /= a[y], ++ z;
now += - cnt[y] * b[y];
cnt[y] = (cnt[y] + z) % m;
now += cnt[y] * b[y];
}
ans += S[now] ++;
}
cout << ans << endl;
return 0;
}
T4
考虑题目所求为两者权值之差,考虑令串 的权值为 \(v_{i} + \frac{1}{2}\sum_{j}^{}LCP(s_{i},s_{j})\)。
那么如果两个串都被一个人选中,LCP 恰好被加了两遍
如果分别被两个人选中,一相减恰好消除。
所以直接对这个权值排序,从大到小以此选择即可。
没改完,std:
#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
template <typename T>
void read(T &x) {
x = 0; char c = getchar(); int f = 0;
for (; !isdigit(c); c = getchar())
f |= c == '-';
for (; isdigit(c); c = getchar())
x = x * 10 + (c ^ '0');
if (f) x = -x;
}
template <typename T>
void write(T x, char ed = '\n') {
if (x < 0) putchar('-'), x = -x;
static short st[30], tp;
do st[++tp] = x % 10, x /= 10; while (x);
while (tp) putchar(st[tp--] | '0');
putchar(ed);
}
#include <algorithm>
const int N = 10005001, M = 100050;
int ch[N][2], siz[N], f[N], ed[M], n, tot = 1;
ll v[M];
char s[M];
int insert(char *s) {
int len = strlen(s + 1), p = 1;
for (int i = 1;i <= len; ++i) {
int c = s[i] - '0';
if (!ch[p][c]) ch[p][c] = ++tot, f[tot] = p;
p = ch[p][c], ++siz[p];
}
return p;
}
#include <assert.h>
int main() {
// freopen ("13.in","r",stdin);
read(n);
for (int i = 1;i <= n; ++i) {
scanf ("%s", s + 1), read(v[i]);
v[i] = v[i] * 2, ed[i] = insert(s);
}
for (int i = 1;i <= n; ++i) {
int p = ed[i];
while (p) v[i] += siz[p] - 1, p = f[p];
}
sort(v + 1, v + n + 1, [&](int x, int y) { return x > y;});
ll ans = 0;
for (int i = 1;i <= n; ++i)
i & 1 ? ans += v[i] : ans -= v[i];
write(ans / 2);
assert(tot < N);
assert(ans % 2 == 0);
return 0;
}
.
本文来自博客园,作者:北烛青澜,转载请注明原文链接:https://www.cnblogs.com/Multitree/articles/17592220.html
The heart is higher than the sky, and life is thinner than paper.
浙公网安备 33010602011771号