2022牛客寒假算法基础集训营2

因【牛客版权】不放题面了

A.小沙的炉石

思路

假设我们攻击了 a a a次,那么 a a a次攻击的伤害范围我们是可以求出来的,伤害最低的打一次回一次蓝的模式,伤害最高是先把所有加蓝卡用完,再攻击a次,然后没提前一个位置使用蓝卡,伤害就会+1(可以抽象为二进制,蓝卡的位置对总伤害的贡献与二进制的1的位置,对答案的贡献类似)

通过假设我们可以得到一个离散区间 [ a 2 , a m + a ( a + 1 ) 2 ] [a^2,am+\frac{a(a+1)}{2}] [a2,am+2a(a+1)],这个是攻击 a a a所有可能伤害。

所以我们对每一个 x x x,判断其与这个区间的关系就可以。

代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int main() {
	ll n, m, k; cin >> n >> m >> k;
	while (k--) {
		ll a, x; cin >> x;
		a = sqrt(x);
		a = min(a, min(n, m + 1));
		if (a * m + a * (1 + a) / 2 < x) cout << "NO" << "\n";
		else cout << "YES" << "\n";
	}
}

F.小沙的算数

思路

因为乘法的优先级是高于加法的,且同级的只有一个运算符,这大大简化了题目难度

我们只需要把乘法的分为一组,加法的分为一组,因为改变乘法组内数字 ,并不影响加法组,同理,改变加法组也一样。

因为取模除法,需要逆元。

反思:当时没过因为偷懒,看数据范围累乘的结果爆不了ll,不取模,直接除,这样就不用写快速幂了,然后wa了,没找到错误就遁了

代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn = 1e6 + 10;
const ll mod = 1e9 + 7;
ll n, q, a[maxn], book[maxn], sum[maxn];
char s[maxn];
ll qpow(ll a, ll x) {
	ll res = 1;
	while (x) {
		if (x & 1) res = res * a % mod;
		a = a * a % mod;
		x >>= 1;
	}
	return res;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> q;
	int t = 1;
	for (int i = 1; i < n; i++) cin >> s[i];
	for (int i = 1; i <= n; i++) cin >> a[i];
	sum[1] = a[1];
	book[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (s[i - 1] == '*') {              
			book[i] = t;
			sum[t] = sum[t] * a[i] % mod;   
		}
		else {                        
			sum[++t] = a[i];
			book[i] = t;
		}
	}
	long long ans = 0;
	for (int i = 1; i <= t; i++) ans = (ans + sum[i]) % mod;
	while (q--) {
		int x, y;
		cin >> x >> y;
		ans = (ans - sum[book[x]] + mod) % mod;   
		sum[book[x]] = sum[book[x]] * qpow(a[x], mod - 2) % mod * y % mod;   
		ans = (ans + sum[book[x]]) % mod;
		a[x] = y;
		cout << ans << endl;
	}
	return 0;
}

G.小沙的身法

思路

简化目的:给定 ( x , y ) (x,y) (x,y),求 x − > y x->y x>y的最短路径的体力消耗,造成体力消耗的原因为从低处往高处走($a[u]<a[v] $)

我们可以建立两个数组(思路为前缀和),load[i]表示从 p o i n t [ 1 ] point[1] point[1]走到 p o i n t [ i ] point[i] point[i]的体力消耗,reload[i]表示从 p o i n t [ i ] point[i] point[i]走到 p o i n t [ 1 ] point[1] point[1]的体力消耗。

因为题目给的地图为无向图,所以最短路径为x->p->y p = l c a ( x , y ) p=lca(x,y) p=lca(x,y)

所以得到答案方程:
a n s = a [ x ] + r e l o a d [ x ] − r e l o a d [ p ] + l o a d [ y ] − l o a d [ p ] ans=a[x]+reload[x]-reload[p]+load[y]-load[p] ans=a[x]+reload[x]reload[p]+load[y]load[p]

代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6 + 10;
ll a[maxn], load[maxn], reload[maxn];
int head[maxn], nex[2 * maxn], w[2 * maxn], dis[maxn], fa[maxn], num[maxn], node[maxn], cnt;

void add(int u, int v) {
	num[u]++;
	w[++cnt] = v;
	nex[cnt] = head[u];
	head[u] = cnt;
}
void dfs(int index, int reindex, int top) {
	node[index] = top;
	fa[index] = reindex;
	load[index] = load[reindex];
	reload[index] = reload[reindex];
	if (a[index] > a[reindex]) load[index] += a[index] - a[reindex];
	else if (a[index] < a[reindex]) reload[index] += a[reindex] - a[index];
	dis[index] = dis[reindex] + 1;
	for (int i = head[index], temp = 0; i != 0; i = nex[i]) {
		if (w[i] == reindex) continue;
		if (temp++ == 0) dfs(w[i], index, top);
		else dfs(w[i], index, w[i]);
	}
	return;
}
int lca(int x, int y){
	while (node[x] != node[y]) {
		if (dis[node[x]] < dis[node[y]]) swap(x, y);
		x = fa[node[x]];
	}
	if (dis[x] < dis[y]) return x;
	else return y;
}
int main() {
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n, m; cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i < n; i++) {
		int x, y; cin >> x >> y;
		add(x, y);
		add(y, x);
	}
	dfs(1, 0, 1);
	while (m--) {
		int x, y; cin >> x >> y;
		int index = lca(x, y);
		cout << a[x] + reload[x] - reload[index] + load[y] - load[index] << "\n";
	}
}

I.小沙的构造

思路

构造,大体思想很好想,一些细节处理比较麻烦~~(因为我太菜了~~

代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long

string arr = "\"!'*+-.08:=^_WTYUIOAHXVM|<>\\/[]{}()";

int main() {
	int n, m; cin >> n >> m;
	if (m == 36 || m > n || (m >= 10 && ((n - 10 + 1) / 2 < (m - 10))) ) {
		cout << -1;
		return 0;
	}
	if (m & 1) {
		if (m <= 11) {
			for (int i = 25; i <= 23 + m - 1; i += 2) cout << arr[i];
			for (int i = 1; i <= n - m + 1; i++) cout << arr[0];
			for (int i = 24 + m - 1; i > 25; i -= 2) cout << arr[i];
		}
		else {
			for (int i = 25; i < 35; i += 2) cout << arr[i];
			for (int i = 1; i <= m - 11; i++) cout << arr[i];
			for (int i = 1; i <= n - 10 - 2 * (m - 11); i++) cout << arr[0];
			for (int i = m - 11; i >= 1; i--) cout << arr[i];
			for (int i = 34; i > 25; i -= 2) cout << arr[i];
		}
	}
	else {
		if (m <= 12) {
			if (n & 1) {
				int temp = 0;
				for (int i = 25; i <= min(33, 23 + m - 1); i += 2, temp++) cout << arr[i];
				cout << arr[0];
				for (int i = 1; i <= n - 2 * temp - 2; i++) cout << arr[1];
				cout << arr[0];
				for (int i = min(34, 24 + m - 2); i > 25; i -= 2) cout << arr[i];
			}
			else {
				int tmep = m;
				for (int i = 25; i <= min(33, 23 + m); i += 2, tmep -= 2) cout << arr[i];
				if (tmep > 0) {
					for (int i = 1; i <= tmep; i++) cout << arr[i - 1];
					for (int i = 1; i <= n - 10 - 2 * (m - 10); i++)  cout << arr[tmep - 1];
					for (int i = tmep; i >= 1; i--) cout << arr[i - 1];
				}
				else {
					for (int i = 1; i <= (n - m) / 2; i++) cout << arr[23 + m];
					for (int i = 1; i <= (n - m) / 2; i++) cout << arr[24 + m];
				}
				for (int i = min(34, 24 + m); i > 25; i -= 2) cout << arr[i];
			}
		}
		else {
			for (int i = 25; i < 35; i += 2) cout << arr[i];
			for (int i = 0; i < m - 10; i++) cout << arr[i];
			for (int i = 1; i <= n - 10 - 2 * (m - 10); i++) cout << arr[0];
			for (int i = m - 11 - (n - 10 - 2 * (m - 10) < 0); i >= 0; i--) cout << arr[i];
			for (int i = 34; i > 25; i -= 2) cout << arr[i];
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LOTRcsl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值