CSP-S2考前综合强化刷题(第五场)
A
首先分析下题目性质
只比天多1
然后只比多2
那么会发现i要花费的天数可以是想化一些天追上i-1,然后在追上的前提下去追...
那么如果我们没追上i-1就追上i-2的话...也一定可以用哪个时间追上
这个东西就比较显然....相邻取min
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e6 + 7;
int n, a[MAXN], ans;
signed main() {
scanf("%lld", &n);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
ans = 1e15;
for(int i = 1; i < n; ++i) {
ans = min(ans, a[i] - a[i + 1]);
}
printf("%lld\n", ans);
return 0;
}
B
曼哈顿距离,屑啊
显然我们前n/2大的都要在左边,后n/2大的在右边
那么我们只需要看看那些位置不满足这个性质,然后把他们任意交换就好了
因为是曼哈顿距离....所以就是后n/2前n/2大的下标之和-前n/2后n/2大的下标之和
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 7;
#define ll long long
ll ans;
int n;
struct rec {
int x, id;
bool operator<(const rec &w)const {
return x < w.x;
}
} a[MAXN];
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i].x);
a[i].id = i;
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n / 2; ++i) {
if(a[i].id > n / 2) {
ans += a[i].id;
}
}
for(int i = n / 2 + 1; i <= n; ++i) {
if(a[i].id <= n / 2) {
ans -= a[i].id;
}
}
printf("%lld\n", ans);
return 0;
}
C
显然我们直接排序然后k个分一组是错误的,因为我们切换字符可以直接砍掉一堆
但是这个东西是可以在trie树上做的
我们把所有串插入trie然后在上面dfs即可,统计每个子树和,然后我们回溯的时候如果子树中够k个就凑一下
因为这样做能保证每个组尽可能的深的地方匹配,所以是对的
时间复杂度
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e6 + 7;
int n, k;
char s[MAXN];
int rt = 1, T = 1;
int ch[MAXN][27];
int ed[MAXN];
inline void ins(char *s, int L) {
int nw = rt;
for(int i = 0; i < L; ++i) {
int t = s[i] - 'a';
if(!ch[nw][t]) {
ch[nw][t] = ++T;
}
nw = ch[nw][t];
}
ed[nw]++;//kk
return ;
}
ll ans;
inline void dfs(int u, int dep) {
for(int i = 0; i < 26; ++i) {
if(ch[u][i]) {
dfs(ch[u][i], dep + 1);
ed[u] += ed[ch[u][i]];
}
}
ans += 1ll * dep * (ed[u] / k);
ed[u] %= k;
return ;
}
int main() {
// freopen("test.in", "r", stdin);
// freopen("test1.out", "w", stdout);
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i) {
scanf("%s", s);
int l = strlen(s);
ins(s, l);
}
dfs(1, 0);
printf("%lld\n", ans);
return 0;
}
D
对于
考虑直接暴力,可以做到
做法就是把每个位置修改一下然后再考虑m次暴力即可
对于
考虑快速回答询问
显然的是这个询问不会很快...此时会发现我们能够二维数点了
李队有一个O(1)回答的做法,好像是根号平衡啊
就是考虑用前缀和分块,然后我们修改复杂度
二维平面上我们就直接扫描线扫过去
可以离线做到一个log,复杂度O(Q \sqrtQ log)
code:
//数据处理题
//超高校级的幸运
//如果数据随机,\sum_K会减少的很快,暴力就快
//如果构造去他妈的
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e5 + 7;
namespace fastIO {
#define BUF_SIZE (1<<20)
static char buf[BUF_SIZE], *p1 = buf, *pend = buf;
inline char nc() {
if(p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
}
return *p1++;
}
inline int read() {
int x = 0;
char s = nc();
for(; !isdigit(s); s = nc());
for(; isdigit(s); s = nc())x = (x << 1) + (x << 3) + s - '0';
return x;
}
}
using namespace fastIO;
int n, m, q, Bas, ccnt;
int home[MAXN], nxt[MAXN], tl[MAXN], tr[MAXN], ans[MAXN];
int q1[MAXN], q2[MAXN], t1, t2, a[MAXN];
inline void ct(int x, int y, int z) {
ccnt++;
nxt[ccnt] = home[x];
home[x] = ccnt;
tl[ccnt] = y;
tr[ccnt] = z;
}
const int BIG = 1e7 + 8;
struct rec {
int u, v, x, y;
rec(int u = 0, int v = 0, int x = 0, int y = 0) : u(u), v(v), x(x), y(y) {};
bool operator<(const rec &w) const {
return u == w.u ? x < w.x : u < w.u;
}
} e[MAXN], qry[MAXN], mda[BIG];
inline void solve1() {
for(int i = 1; i <= t1; ++i) {
int id = q1[i];
for(int k = home[qry[id].v]; k; k = nxt[k]) {
int L = tl[k];
int R = tr[k];
for(int j = L; j <= R; ++j)
a[j] = i;
}
for(int j = 1; j <= m; ++j) {
if(a[e[j].u] == i && a[e[j].v] == i) {
ans[qry[id].v] = 1;
break;
}
}
}
return ;
}
struct bit {
#define lowbit(x) (x&(-x))
int tr[MAXN];
inline void add(int x, int V) {
for(; x <= n; x += lowbit(x))
tr[x] += V;
}
inline int qry(int x) {
int ret = 0;
for(; x; x -= lowbit(x))ret += tr[x];
return ret;
}
} tre;
#define lowbit(x) (x&(-x))
inline void solve2() {
int tot = 0;
for(int t = 1; t <= t2; ++t) {
int i = q2[t];
for(int j = home[qry[i].v]; j; j = nxt[j]) {
for(int k = j; k; k = nxt[k]) {
mda[++tot] = (rec) {
tl[k] - 1, tl[j], tr[j], -qry[i].v
};
mda[++tot] = (rec) {
tr[k], tl[j], tr[j], qry[i].v
};
}
}
}
for(int i = 1; i <= m; ++i) {
mda[++tot] = (rec) {
e[i].u, e[i].v, -1
};
}
sort(mda + 1, mda + tot + 1);
for(int i = 1; i <= tot; ++i) {
if(mda[i].x == -1) {
tre.add(mda[i].v, 1);
} else if(mda[i].y > 0) {
if(mda[i].v == 1)ans[mda[i].y] += tre.qry(mda[i].x);
else ans[mda[i].y] += tre.qry(mda[i].x) - tre.qry(mda[i].v - 1);
} else {
mda[i].y = -mda[i].y;
if(mda[i].v == 1)ans[mda[i].y] -= tre.qry(mda[i].x);
else ans[mda[i].y] -= tre.qry(mda[i].x) - tre.qry(mda[i].v - 1);
}
}
return ;
}
int main() {
// freopen("test.in", "r", stdin);
n = read();
m = read();
q = read();
for(int i = 1; i <= m; ++i) {
e[i].u = read();
e[i].v = read();
if(e[i].u > e[i].v)swap(e[i].u, e[i].v);
}
for(int i = 1; i <= q; ++i) {
qry[i].u = read();
qry[i].v = i;
for(int j = 1, x, y; j <= qry[i].u; ++j) {
x = read();
y = read();
ct(i, x, y);
}
}
Bas = 1e4;
int res = 4e6; //循环展开
sort(qry + 1, qry + q + 1);
int i = q;
int cnt = 1e8 / max(n, m);
for(; i >= 1; --i) {
if(qry[i].u * qry[i].u >= Bas && cnt) {
q1[++t1] = i;
--cnt;
} else {
break;
}
}
int j = 1;
for(; j <= i; ++j) {
if(res) {
q2[++t2] = j;
res = max(0, res - qry[j].u * qry[j].u);
} else {
q1[++t1] = j;
}
}
solve1();//暴力1
solve2();//暴力2
for(int i = 1; i <= q; ++i) {
if(ans[i])printf("GG\n");
else printf("SAFE\n");
}
return 0;
}