zoukankan      html  css  js  c++  java
  • 【考试总结】欢乐模拟赛_Day2

    (T1)

    题目描述

    在仙界中有着 (n) 位神仙, 每位神仙用一个 (1 ∼ n) 的特异编号表示, 老祖 (ChitongZ) 的编号为 (1) .
    除去至尊至圣, 统管仙界的老祖 (ChitongZ) 外, 其他的 (n − 1) 位神仙都有唯一的尊师, 并且形成了一个树形结构.
    老祖 (ChitongZ) 为了提升仙界综合实力, 倡导神仙们进行修炼.
    但每次修炼是需要一颗金丹的, 若一位神仙自己没有金丹, 就需要向自己的尊师索取一颗. 若尊师也没有, 则尊师会向他的尊师索取一颗, 以此类推, 直到索取到一颗金丹, 修炼结束后这颗金丹就会被消耗掉.

    (Solution)

    预估 (100pts) ,数组开小了只有 (60pts)

    其实这道题很多做法,我想了两个,都记录一下

    (EP.1)

    类似树剖,先做一个 (dfs) ,给每个点标上 (dfs)(id[x]),用线段树维护覆盖

    对于一个点 (x) ,离它最近的被标记的点(即 (ans))是 所有可以覆盖它的点中 (id) 最大的,所以在每次线段树做 (pushdown) 的时候取 (max) ,输出的时候再转化为原答案

    (EP.2)

    用并查集维护

    把所有操作保存下来,构造出一颗树,树的状态为所有操作完成后,再做一个 (dfs) ,若点 (x) 被标记过,则 (s[x] = x) ,不然指向 (fa[x])

    然后倒着操作,即给一个点标记变为去掉一个点的标记,若这个点没有标记了,则把 (s[x]) 指向 (fa[x])

    Code

    只有 (EP.2) 的代码233

    #include<bits/stdc++.h>
    #define ll long long
    #define F(i, x, y) for(int i = x; i <= y; ++ i)
    using namespace std;
    int read();
    const int N = 5e6 + 5;
    const ll B1 = 37;
    const ll P1 = 19260817;
    const ll B2 = 137;
    const ll P2 = 998244353; 
    int n, m, x;
    int s[N], d[N], fa[N], k[N]; 
    ll ans1, ans2;
    struct kk{
    	int edge;
    	char sta;
    }Q[N];
    int head[N], cnt;
    struct node{
    	int ver, next;
    }a[N << 1];
    void add(int x, int y)
    {
    	++ cnt;
    	a[cnt].ver = y, a[cnt].next = head[x], head[x] = cnt;
    }
    void dfs(int x, int f)
    {
    	s[x] = d[x] ? x : f, fa[x] = f;
    	for(int i = head[x]; i; i = a[i].next)
    		if(a[i].ver != f)
    			dfs(a[i].ver, x);	
    }
    int search(int x)
    {
    	return x == s[x] ? x : s[x] = search(s[x]);
    }
    int main()
    {
    	freopen("decomposition.in","r",stdin);
    	freopen("decomposition.out","w",stdout);
    	n = read(), m = read();
    	F(i, 2, n) x = read(), add(x, i), add(i, x);
    	F(i, 1, m)
    	{
    		Q[i].sta = read(), Q[i].edge = read();
    		if(Q[i].sta == 2) ++ d[Q[i].edge];
    	} 
    	dfs(1, 0), s[1] = 1, fa[1] = 1;
    	for(int i = m; i >= 1; -- i)
    	{
    		if(Q[i].sta == 1) k[i] = search(Q[i].edge);
    		else 
    		{
    			-- d[Q[i].edge];
    			if(! d[Q[i].edge]) s[Q[i].edge] = fa[Q[i].edge];
    		}
    	}
    	F(i, 1, m) if(k[i])
    		ans1 = (ans1 * B1 + k[i]) % P1, ans2 = (ans2 * B2 + k[i]) % P2;
    	printf("%lld %lld", ans1, ans2);
    	return 0;
    }
    int read()
    {
    	int x = 0;
    	char c = getchar();
    	while(c < '0' || c > '9') c = getchar();
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x;
    }
    

    (T2)

    题目描述

    (n) 个人依次进入观影厅, 观看 (Weathering with You) .
    观影厅只有一排座位, 第 (1) 个人进入时, 会选择第 (1) 个座位坐下.
    由于观影厅空调坏掉了, 十分炎热, 之后的每个人进入时, 他会选择一个离最近的已经坐下的人尽可能远的空位.
    如果有多个空位使得离最近的人同样远, 则他会从其中随机选取一个.
    若有两个人选择的位置相邻, 他们就会不满意.
    为了让所有人都满意, 观影厅至少需要有几个座位呢?

    (Solution)

    根据各种打表找规律可得出

    [f(x) = x + 2^{1+⌊log_2(x−2)⌋}. ]

    然后用高精度写

    比较方便的写法是,用 (2) 不断往上乘,一边乘一边判断大小,最后加一个 (n)

    这样就只要写高精乘低精,判断大小,高精度加法,比较好写

    还有特殊情况,(f(1) = 1)(f(2) = 3),我没想到然后就只有 (95pts)

    Code

    #include<bits/stdc++.h>
    #define F(i, x, y) for(int i = x; i <= y; ++ i)
    using namespace std;
    int read();
    const int N = 2e3 + 5;
    char z;
    int a[N], alen;
    int b[N], blen;
    int c[N], clen;
    void mul(int b[])
    {
    	int x = 0;
    	F(i, 1, blen) x += b[i] * 2, b[i] = x % 10, x = x / 10;
    	if(x) b[++ blen] = x;
    }
    bool comp(int a[], int b[])
    {
    	int x = 2, clen = blen;
    	F(i, 1, blen) c[i] = b[i];
    	F(i, 1, clen)
    	{
    		c[i] += x, x = c[i] / 10, c[i] %= 10;
    		if(! x) break;
    	}
    	if(x) c[++ clen] = x;
    	if(alen != clen) return alen > clen;
    	for(int i = alen; i >= 1; -- i)
    		if(a[i] != c[i]) return a[i] > c[i];
    	return true;
    }
    int main()
    {
    	freopen("tenki.in","r",stdin);
    	freopen("tenki.out","w",stdout);
    	while(scanf("%c", &z) != EOF) c[++ alen] = z - '0';
    	-- alen;
    	F(i, 1, alen) a[alen - i + 1] = c[i];
    	if(alen == 1 && (a[1] == 1 || a[1] == 2))
    	{
    		puts(a[1] == 1 ? "1" : "3");
    		return 0;
    	}
    	blen = 1, b[blen] = 2;
    	while(comp(a, b)) mul(b);
    	memset(c, 0, sizeof(c));
    	F(i, 1, max(alen, blen))
    	{
    		c[i] = c[i] + a[i] + b[i];
    		c[i + 1] = c[i] / 10, c[i] %= 10;
    	}
    	clen = max(alen, blen);
    	if(c[clen + 1]) ++ clen;
    	for(int i = clen; i >= 1; -- i) printf("%d", c[i]); 
    	return 0;
    }
    /*
    q = (log2 (n - 2)) + 1;
    ans = 2 ^ q + n;
    */
    

    (T3)

    题目描述

    给定一个正整数 (k) , 以及一棵 (n) 个节点的以 (1) 为根的有根树, 边有长度.
    (LCA(a, b)) 表示 (a)(b) 在树上的最近公共祖先, (dist(a)) 表示树根到 (a) 的距离.
    每个节点可以是黑色或白色, 初始时每个节点的颜色为白色.
    进行 m 次操作, 每次操作是以下两种形式之一:
    修改操作: 给出一个修改节点 (x) , 将节点 (x) 染上黑色. 保证 (x) 在染色前为白色.
    询问操作: 给出一个询问节点 (x) , 记所有黑点形成的集合为 (S) , 求出下面式子的值:

    [sum_{y∈S}F( dist ( LCA ( x, y ) ) ) ]

    其中函数 (F) 定义为,

    [F(x) =sumlimits_{i=1}^xi^k ]

    由于答案可能很大, 只需要输出答案对 (P = 998244353) 取模的结果

    (Solution)

    这道题的难点:

    (1.)题意比较绕,要求的答案函数套函数,很容易弄错
    (2.)列出式子并把式子化简,将定值和要维护的值拆开

    肝了半个下午 (+) 半个晚自习,心力交瘁...不过真的是道好题!!

    ((btw),膜一膜 (xiaolilsq) 大佬,本来我都没信心把这道题改出来233,结果他讲题讲得好清楚然后就改掉了!())

    (Code)

    #include<bits/stdc++.h>
    #define ll long long
    #define ls k << 1
    #define rs (k << 1) + 1
    #define mid ((l + r) >> 1)
    #define F(i, x, y) for(int i = x; i <= y; ++ i)
    using namespace std;
    int read();
    const int N = 1e5 + 5;
    const int M = 1e7 + 5;
    const int mod = 998244353;
    int n, m, s;
    ll x, y, num, vis[N], f[M], dist[N];
    ll tree[N << 2], atree[N << 2], tag[N << 2], a[N];
    ll dep[N], size[N], fa[N], son[N], id[N], top[N];
    ll head[N], cnt, ver[N << 1], edge[N << 1], nxt[N << 1];
    void add(int x, int y, int z)
    {
    	ver[++ cnt] = y, edge[cnt] = z, nxt[cnt] = head[x], head[x] = cnt;
    }
    ll qpower(ll x, int y)
    {
    	ll res = 1;
    	while(y)
    	{
    		if(y & 1) res = res * x % mod;
    		x = x * x % mod, y >>= 1;
    	}
    	return res;
    }
    void dfs1(int x, int ffa)
    {
    	dep[x] =dep[ffa] + 1, size[x] = 1, fa[x] = ffa;
    	int maxn = -1;
    	for(int i = head[x]; i; i = nxt[i])
    		if(ver[i] != ffa)
    		{
    			dist[ver[i]] = dist[x] + edge[i], dfs1(ver[i], x), size[x] += size[ver[i]];
    			if(size[ver[i]] > maxn) son[x] = ver[i], maxn = size[ver[i]];
    		}
    }
    void dfs2(int x, int topfa, int ffa)
    {
    	id[x] = ++ num, top[x] = topfa;
    	a[id[x]] = (f[dist[x]] - f[dist[ffa]] + mod) % mod;
    	if(! son[x]) return;
    	dfs2(son[x], topfa, x);
    	for(int i = head[x]; i; i = nxt[i])
    		if(ver[i] != fa[x] && ver[i] != son[x])
    				dfs2(ver[i], ver[i], x);
    }
    void pushup(int l, int r, int k)
    {
    	atree[k] = (atree[ls] + atree[rs]) % mod;
    }
    void build(int l, int r, int k)
    {
    	if(l == r) 
    	{
    		tree[k] =  a[l] % mod;
    		return;
    	}
    	build(l, mid, ls);
    	build(mid + 1, r, rs);
    	tree[k] = (tree[ls] + tree[rs]) % mod; 
    }
    void pushdown(int l, int r, int k)
    {
    	if(! tag[k]) return;
    	atree[ls] = (tree[ls] * tag[k] % mod + atree[ls]) % mod;
    	atree[rs] = (tree[rs] * tag[k] % mod + atree[rs]) % mod;
    	tag[ls] += tag[k], tag[rs] += tag[k];
    	tag[k] = 0;
    }
    void modify(int l, int r, int k, int x, int y, int v)
    {
    	if(l >= x && r <= y) 
    	{
    		atree[k] = (tree[k] * v % mod + atree[k]) % mod, tag[k] += v;
    		return;
    	}
    	pushdown(l, r, k);
    	if(x <= mid) modify(l, mid, ls, x, y, v);
    	if(y > mid) modify(mid + 1, r, rs, x, y, v);
    	pushup(l, r, k);
    }
    ll query(int l, int r, int k, int x, int y)
    {
    	if(l >= x && r <= y) return atree[k];
    	pushdown(l, r, k);
    	ll res = 0;
    	if(x <= mid) res = (res + query(l, mid, ls, x, y)) % mod;
    	if(y > mid) res = (res + query(mid + 1, r, rs, x, y)) % mod;
    	return res;
    }
    void modify_range(int x)
    {
    	if(vis[x]) return;
    	vis[x] = 1;	
    	while(top[x] != 1)
    	{
    		modify(1, n, 1, id[top[x]], id[x], 1);
    		x = fa[top[x]];
    	}
    	modify(1, n, 1, 1, id[x], 1);
    }
    ll query_range(int x)
    {
    	ll res = 0; 
    	while(top[x] != 1)
    	{
    		res = (res + query(1, n, 1, id[top[x]], id[x])) % mod;
    		x = fa[top[x]];
    	}
    	res = (res + query(1, n, 1, 1, id[x])) % mod;
    	return res;
    }
    int main()	
    {
    	freopen("mafumafu.in","r",stdin);
    	freopen("mafumafu.out","w",stdout);
    	n = read(), m = read(), s = read();
    	F(i, 1, M - 1) f[i] = (f[i - 1] + qpower(i, s) % mod) % mod;
    	F(i, 2, n) x = read(), y = read(), add(x, i, y), add(i, x, y);
    	dfs1(1, 0), dfs2(1, 1, 0), build(1, n, 1);
    	while(m --)
    	{
    		y = read(), x = read();
    		if(y == 1) modify_range(x);
    		if(y == 2) printf("%lld
    ", query_range(x));
    	}
    	return 0;
    }
    int read()
    {
    	int x = 0, f = 1;
    	char c = getchar();
    	while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * f;
    }
    

    总结

    排名(:5/17)

    预估分数(:100 + 100 + 0)

    实际分数(:60 + 95 + 0)

    (1.)(0202) 了我怎么还犯数组开小了这种错误。。。
    (2.)(0202) 了我怎么还反不考虑特殊情况这种错误。。。

    总体来说今天还行,调整了考试状态,尽力地拿分,其实写完前两道题后还剩半个小时,打了 (t3) 的暴力,可惜没时间调了,不过这种习惯还是要坚持,抓住每一分每一秒;但是还是有一些**错误,爆锤我寄几!!!

  • 相关阅读:
    Elastic Beanstalk 环境的 Auto Scaling 组
    Welcome to AWS Greengrass Demo on RaspBerry Pi 4B with OpenVino
    Amazon SQS 延迟队列
    跟踪、记录和监控 API Gateway API
    AWS Lambda 别名简介
    GenerateDataKeyWithoutPlaintext & GenerateDataKey
    高级 AWS Elastic Beanstalk 环境配置 » 使用自定义 Amazon 系统映像 (AMI)
    Write-Through缓存策略 ElastiCache
    十一、函数递归,算法二分法,三元表达式,列表字典生成式,匿名函数,内置函数
    十、装饰器,闭包
  • 原文地址:https://www.cnblogs.com/Bn_ff/p/12682101.html
Copyright © 2011-2022 走看看