1002考试
1002考试总结
T1
题目大意:
小Y得到了一个长度为𝑛的序列𝑎。选定一个区间\([𝑙,𝑟](𝑙≠𝑟)\),设区间中的最大值为𝑥,最小值为𝑦,则他定义该区间的价值为(𝑥−𝑦) / (𝑟−𝑙)。现在,他想让你找出这个序列价值最大的区间。你只需输出最大的价值下取整的结果。
没思路,直接大保利。
正解非常的巧妙。首先我们知道,这个答案的左右端点一定是在最大值/最小值上面,因为再大一点答案要么不会改变,要么会出现新的最大值/最小值。我们发现\((x - y) / (r - l)\)特别像一个东西,我们把\((r, x), (l, y)\)转化成二维平面上的点,那么要求的那个东西就是斜率:\(abs(x - y) / (r - l)\)。现在题面转化成了求斜率最大的两个点。
我们假设现在有三个点,其中两个点相连,如果第三个点在这条线上,那么斜率不会改变;如果第三个点在这条线上方,则它可以与第一个点形成更大的斜率;如果第三个点在这条线下方,则它可以与第二个点形成更大的斜率。就像这样:
所以我们可以得出结论:斜率最大的两个点一定是相邻的两个点。所以现在我们只需对相邻的点找答案就好了。
真是妙蛙种子吃了妙脆角妙进了米奇妙妙屋妙到家了
#include <bits/stdc++.h>
using namespace std;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1 ++)
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
int T, n, x, last, ans;
int main() {
T = read();
while(T --> 0) {
n = read(); ans = 0;
for(int i = 1;i <= n; i++) {
last = x; x = read();
if(i != 1) ans = max(ans, abs(x - last));
}
printf("%d\n", ans);
}
fclose(stdin); fclose(stdout);
return 0;
}
T2
题目大意:
小Y得到了一个长度为𝑛的画板和𝑚支画笔。经过尝试,他发现编号为𝑖的画笔能够对画板的第𝑙𝑖格到第𝑟𝑖格染色。现在小Y有𝑞次询问,每次他想知道编号在[𝑥,𝑦]内的画笔能否将画板上的区间[𝑠,𝑡]中的每一格都染色。
开始想着用主席树做,拿了50pts。貌似爆空间了,和暴力分一样mdzz。
正解也是很巧妙的。
我们先把询问离线下来,然后按\(y\)的大小排个序。开一颗线段树,往里面覆盖颜色。也就是说当前的询问是要把1到y所有画笔按顺序涂好色,此时序列上就有了各种颜色。然后我们查询一下\([s, t]\)区间内的最小值,看是否小于\(x\),如果小于,则说明\([x, y]\)这些画笔无法将这个区间完全染色,反之则符合要求。
#include <bits/stdc++.h>
#define ls(o) (o << 1)
#define rs(o) (o << 1 | 1)
#define mid ((l + r) >> 1)
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1e6 + 5;
int n, m, Q, tot, now;
int ans[N];
struct tree { int tag, Min; } t[N << 2];
struct pan { int l, r; } a[N];
struct que { int x, y, l, r, id; } q[N];
int cmp(que a, que b) { return a.y < b.y; }
int mmp(que a, que b) { return a.id < b.id; }
void up(int o) {
t[o].Min = min(t[ls(o)].Min, t[rs(o)].Min);
}
void modify(int o, int k) {
t[o].tag = k; t[o].Min = k;
}
void down(int o) {
if(t[o].tag) modify(ls(o), t[o].tag), modify(rs(o), t[o].tag), t[o].tag = 0;
}
void change(int o, int l, int r, int x, int y, int col) {
if(x <= l && y >= r) { t[o].tag = t[o].Min = col; return ; }
down(o);
if(x <= mid) change(ls(o), l, mid, x, y, col);
if(y > mid) change(rs(o), mid + 1, r, x, y, col);
up(o);
}
int query(int o, int l, int r, int x, int y) {
if(x <= l && y >= r) { return t[o].Min; }
down(o);
int res = 1e9;
if(x <= mid) res = min(res, query(ls(o), l, mid, x, y));
if(y > mid) res = min(res, query(rs(o), mid + 1, r, x, y));
return res;
}
int main() {
n = read(); m = read(); Q = read();
for(int i = 1;i <= m; i++) a[i].l = read(), a[i].r = read();
for(int i = 1;i <= Q; i++) q[i].x = read(), q[i].y = read(), q[i].l = read(), q[i].r = read(), q[i].id = i;
sort(q + 1, q + Q + 1, cmp); now = 0;
for(int i = 1;i <= Q; i++) {
while(now < q[i].y) now ++, change(1, 1, n, a[now].l, a[now].r, now);
int tmp = query(1, 1, n, q[i].l, q[i].r);
tmp >= q[i].x ? ans[q[i].id] = 1 : ans[q[i].id] = 0;
}
for(int i = 1;i <= Q; i++) printf("%d\n", ans[i]);
fclose(stdin); fclose(stdout);
return 0;
}
T3
题目大意:
小Y正在A国游玩。该国共有𝑛个城市,地图可以抽象为一张有向无环图。小Y的旅行共有𝑞天,每天他都会选取一个新的起点和终点,同时每天都会有一些城市无法通行。现在小Y想要知道每一天他可能的旅行路线数量。
首先可以预处理出每个点之间的路径数目\(f[x][y]\)。
对于每个询问我们可以用总的路径条数减去经过坏点的路径条数。
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 1005, M = 1e5 + 5, mod = 1e9 + 7;
int n, m, q, cnt;
int c[N], g[N], f[N][N], in[N], vis[N], head[N];
struct edge { int to, nxt; } e[M];
queue <int> que;
void add(int x, int y) {
e[++cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y;
}
void dfs(int x) { //我又一次在这挂了,写int会全部超时,你本机还调不出来,我吐了
vis[x] = 1; f[x][x] = 1;
for(int i = head[x] ; i ; i = e[i].nxt){
int y = e[i].to; if(!vis[y]) dfs(y);
for(int j = 1 ; j <= n ; j ++) (f[x][j] += f[y][j]) %= mod;
}
}
int main() {
n = read(); m = read(); q = read();
for(int i = 1, x, y;i <= m; i++) x = read(), y = read(), add(x, y);
for(int i = 1;i <= n; i++) if(!vis[i]) dfs(i);
for(int i = 1;i <= q; i++) {
int s = read(), t = read(), k = read();
for(int j = 1;j <= n; j++) in[j] = 0;
for(int j = 1;j <= k; j++) c[j] = read();
for(int l = 1;l <= k; l++)
for(int r = 1;r <= k; r++)
if(l == r || !f[c[l]][c[r]]) continue; else in[r] ++;
for(int j = 1;j <= k; j++) g[j] = f[s][c[j]];
for(int j = 1;j <= k; j++) if(!in[j]) que.push(j);
while(!que.empty()) {
int x = que.front(); que.pop();
for(int j = 1;j <= k; j++) {
if(j == x || !f[c[x]][c[j]]) continue;
g[j] -= 1ll * g[x] * f[c[x]][c[j]] % mod; (g[j] += mod) %= mod;
in[j] --; if(!in[j]) que.push(j);
}
}
int ans = f[s][t];
for(int j = 1;j <= k; j++) ans -= 1ll * g[j] * f[c[j]][t] % mod, ans %= mod;
(ans += mod) %= mod;
printf("%d\n", ans);
}
fclose(stdin); fclose(stdout);
return 0;
}