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;
}
posted @ 2020-10-04 07:13  C锥  阅读(106)  评论(0编辑  收藏  举报