ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spoj day1-2

2022-07-11 23:00:17  阅读:158  来源: 互联网

标签:return int ll day1 fa spoj ans find


A.国王的游戏

https://www.luogu.com.cn/problem/P1080

题意:

国王和n个大臣分别在左右手写下一个数,,从国王开始按一定顺序,每个大臣获得金币数为其前面包括国王左手的数的乘积除以自己右手写的数,求大臣最多获得金币数的最小值

思路:

这个贪心不是那么容易贪出来。考虑相邻两个大臣i,j的相对位置,其先后顺序只对i,j的金币产生影响
设i,j前面的乘积为x,大臣i,j的金币为 \(w_i,w_j\)
如果先i后j,\(w_{i1} = x / a_i.r, w_{j1} = x * a_i.l / a_j.r\)
如果先j后i,\(w_{j2}= x / a_j.r, w_{i2} = x * a_j.l / a_i.r\)
显然有
\(w_{j2} < w_{j1} , w_{i2} > w_{i1}\)
对答案产生的影响 \(ans_1 = max(w_{i1},w_{j1}), ans_2 = max(w_{i2},w_{j2})\)
若想使产生的影响更小
假设令 \(ans_1 < ans_2\)
那么就有 $ w_{i2} > w_{j1} $
有 $ a_i.l / a_j.r < a_j.l / a_i.r$
即 \(a_i.l *a_i.r < a_j.l * a_j.r\)
所以我们要把左右两项的乘积大的放在后面
因为这题有一些不友好的数据比如2166489661101032350678866897536628698296804147316726878162441737980268621335310233327258927458239967674879428851028800069063620140885606400000000000000000
所以需要使用数组模拟高精度乘除法,数组模拟比较max等运算

代码:

#include <bits/stdc++.h>
#define ll unsigned long long
#define maxn 10005
using namespace std;
int n, s[maxn + 100], t[maxn + 100], ans[maxn + 100]; 
pair<int, int> p[maxn + 100];
bool compare (pair<int, int> &x, pair<int, int> &y) {
	return (ll)(x.first * x.second) < (ll)(y.first * y.second);
}
bool check(int *a, int *b) {
	for (int i = maxn; i >= 0; i--) {
		if (a[i] > b[i]) return 1;
		else if (a[i] < b[i]) return 0;
	}
	return 1;
} 
void multii (int *b, int x) {
	for (int i = 0; i <= maxn; i++) b[i] *= x;
	for (int i = 0; i <= maxn; i++) {
		b[i + 1] += b[i] / 10;
		b[i] %= 10;
	}
}
void div(int *a, int *b, int x) {
	memset(b, 0, sizeof b);
	int res = 0;
	for (int i = maxn; i >= 0; i--) {
		res = res * 10 + a[i];
		b[i] = res / x;
		res %= x;
	}
}
void cpy(int *a, int *b) {
	for (int i = 0; i <= maxn; i++) a[i] = b[i];
}
int main () {
	cin >> n;
	for (int i = 0; i <= n; i++) cin >> p[i].first >> p[i].second;
	sort(p + 1, p + n + 1, compare);
	s[0] = 1;
	for (int i = 0; i <= n; i++) {
		div(s, t, p[i].second);
		if (check(t, ans)) cpy(ans, t);
		multii(s, p[i].first);
		
		
	}
	bool ok = 0;
	for (int i = maxn; i >= 0; i--) {
		if (ans[i] != 0 && !ok) ok = 1;
		if (ok) cout << ans[i];
	}
	cout << endl;
//	for (int i = 1; i <= n; i++) cout << p[i].first << p[i].second << endl;
	return 0;
}

B.维护序列

线段树懒标板子题

E.Road Reform

https://codeforces.com/problemset/problem/1468/J

题意:

给定n个定点,m条边,k
构造图的一颗生成树,对于其中的边,进行+-1操作,使得边权值最大的一条正好等于k,求最小操作次数

思路:

贪心的优先选择<k的边
将边从小到大排序
先将边权<k的边加入连通块,如果整张图连通,尝试用一条>=k且绝对值之差更小的边替换
如果不连通,依次用>k的边进行连通。
第二种情况下累加和需要开long long
我写的find函数时间复杂度过高导致TLE了

int find (int x) {
	if (fa[x] == x) return x;
	else return find(fa[x]);
}

应该写为

int find (int x) {
	return fa[x] == x ? fa[x] : fa[x] = find(fa[x]); 
}

确实时间复杂度不太一样

代码:

#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 200010
#define maxm 400010
using namespace std;
struct node {
	int x, y, z;
} edge[maxm];
int fa[maxn], n, m, k, t;
bool compare (node x, node y) {
	return x.z < y.z;
}
int find (int x) {
	return fa[x] == x ? fa[x] : fa[x] = find(fa[x]); 
}
void solve() {
		int cnt = 0;
		scanf("%d%d%d", &n, &m, &k);
		for (int i = 1; i <= n; i++) fa[i] = i;
		for (int i = 1; i <= m; i++) scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].z);
		sort(edge + 1, edge + m + 1, compare);	
		for (int i = 1; i <= m; i++) {
			if (edge[i].z >= k) continue;
			int a = edge[i].x, b = edge[i].y;
			a = find(a), b = find(b);
			if (a != b) fa[a] = b, cnt++;
		}
		if (cnt == n - 1) {
			int ans = INF;
			for (int i = 1; i <= m; i++) ans = min(ans, abs(edge[i].z - k));
			printf("%d\n", ans);
		}
		else {
			ll sum = 0;
			for (int i = 1; i <= m; i++) {
				if (edge[i].z < k) continue;
				int a = edge[i].x, b = edge[i].y;
				a = find(a), b = find(b);
				if (a != b) fa[a] = b, sum += edge[i].z - k;
			}
			printf("%lld\n", sum);
		}
}
int main () {
	//ios :: sync_with_stdio(false), cin.tie(0), cout.tie(0);
	scanf("%d", &t);
	while (t--) solve();
	return 0;
}

G.plant

题意:

找规律

代码:

#include <bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
ll d, res = 1;
ll ksm(ll a, ll b, ll m) {
	ll ans = 1;
	while (b) {
		if (b & 1) ans = (ans * a) % m;
		a = (a * a) % m;
		b >>= 1;
	}
	return ans;
}
int main () {
	cin >> d;
	if (!d) cout << "1" << endl;
	else {
		res = ksm(2, d - 1, mod) + ksm(2, 2 * d - 1, mod);
		cout << res % mod << endl;
	}
	return 0;
}

标签:return,int,ll,day1,fa,spoj,ans,find
来源: https://www.cnblogs.com/misasteria/p/16468310.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有