第五天打卡 Codeforces Round #600 (Div. 2)

A题:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5+10;
int a[N],b[N];
int main(){
	int t;
	scanf("%d",&t);
	while(t--)
	{
		
		int n;
		scanf("%d",&n);
		int need = -9999999;
		bool ok = true;
		for(int i=0;i<n;i++)scanf("%d",&a[i]);
		for(int i=0;i<n;i++)scanf("%d",&b[i]);
		for(int i=0;i<n;i++)
		{
			if(a[i]==b[i])continue;
			else if(a[i]>b[i])
			{
				ok=false;
				break;
			}
			else if(need==-9999999)
			{
				need = a[i]-b[i];
				i++;
				while(need==a[i]-b[i])i++;
				i--;
			}
			else 
			{
				ok=false;
				break;
			}
			
		}
		if(ok==true)printf("YES\n");
		else printf("NO\n");
	}
} 

B题:模拟就完事儿

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int a[N];
int n;
set<int>s;
map<int, int>mp;
vector<int>ans;
int main()
{
	n = read();
	upd(i, 1, n)a[i] = read();
	int last = -1;
	upd(i, 1, n)
	{
		if (s.empty())
		{
			mp.clear();
			if (a[i] < 0)
			{
				printf("%d\n", -1);
				return 0;

			}
			else
			{
				mp[a[i]] ++;
				s.insert(a[i]);
			}
			if (last == -1)last = 1;
			else {
				ans.push_back(i - last);
				last = i;
			}
		}
		else
		{
			if (a[i] > 0)
			{
				if (s.find(a[i]) != s.end()||mp[a[i]]==1)
				{
					printf("%d\n", -1);
					return 0;

				}
				else { s.insert(a[i]); mp[a[i]] = 1; }
			}
			else
			{
				if (s.find(-a[i]) == s.end())
				{
					printf("%d\n", -1);
					return 0;

				}
				else
				{
					s.erase(-a[i]);
				}
			}
		}
	}
	if (s.size() != 0)
	{
		printf("%d\n", -1);
		return 0;
	}
	else
	{
		ans.push_back(n+1-last);
	}
	printf("%d\n", ans.size());
	for (auto k : ans)
	{
		printf("%d ", k);
	}
	return 0;
}

C题:乱搞前缀

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int N = 2e5+10;
ll pre[N];
ll a[N];
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	sort(a+1,a+1+n);
    ll ans = 0;
	for(int i=1;i<=n;i++){
		if(i<=m)
		{
			ans+=a[i];
			pre[i]+=a[i];
		}
	    else
		{
	    	if(i%m==0)
	    	{
	    		pre[m]+=a[i];
	    		ans+=pre[m];
			}
			else
			{
				pre[i%m]+=a[i];
				ans+=pre[i%m];
			}
		}
		printf("%lld ",ans);
	}
} 

D题:dsu
题意:要求如果i能够连接到j(j>i)的话,那么i必须要和i+1,i+2…,j-2,j-1相连接。
思路:运用并查集。我们每一个并查集记录当前并查集的最大值和最小值,如果并查集大小==max-min+1,那么说明这个集合一定是符合题意的,否则,从min+1开始遍历,把所有不在这个集合的集合全部插入到该集合中。遍历操作最多o(n)次。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
int n, m;
const int N = 2e5 + 10;
vector<int>vec[N];
int height[N];
int pr[N];
int maxn[N];
int minn[N];
int ans = 0;
void init()
{
	upd(i, 0, n)
	{
		height[i] = 1;
		pr[i] = i;
		maxn[i] = i;
		minn[i] = i;
	}
}
int find_pr(int f)
{
	return pr[f] == f ? f : pr[f] = find_pr(pr[f]);
}
void unit(int u, int v)
{
	u = find_pr(u);
	v = find_pr(v);
	if (u == v)return;
	if (height[u] < height[v])swap(u, v);
	maxn[u] = max(maxn[u], maxn[v]);
	minn[u] = min(minn[u], minn[v]);
	pr[v] = u;
	height[u] += height[v];
}
bool same(int u, int v)
{
	return find_pr(u) == find_pr(v);
}
void work(int u)
{
	u = find_pr(u);
	int nowmax = maxn[u];
	int nowmin = minn[u];
	if (nowmax - nowmin + 1 == height[u])return;
	upd(i, nowmin, nowmax)
	{
		if (same(nowmin, i))continue;
		ans++;
		unit(nowmin, i);
	}
}
int main()
{
	n = read();
	m = read();
	int u, v;
	int st = 1e9; int ed = 0;
	init();
	upd(i, 1, m)
	{
		u = read(), v = read();
		st = min(st, u); st = min(st, v);
		ed = max(ed, u); ed = max(ed, v);
		vec[u].push_back(v);
		vec[v].push_back(u);
		unit(u, v);
	}
	upd(i, st, ed)
	{
		work(i);

	}
	printf("%d\n", ans);
}

E题:思维加dp
题意:给出n个点,以这个一点为中心,初始有向两边的一个覆盖范围,每一次加长1个单位(左右同时)消耗为1,求最小消耗使得1-m被覆盖。
题解:看着其实有点像manacher的意思。我们维护dp[i]表示1-i区间被覆盖的最小解。那么对于i这个点,有两种情况。
1:i落在了某一个的初始区间x内,这个时候dp可以写成
dp[i]=dp[x-left],表示i这个点和这个初始区间的左端点-1那个点,贡献相同。
2:i没有落在某一个初始区间。我们可以把dp写成
dp[i]=dp[m]+val(m=某一个区间扩展过后的左端点-1,val等于该区间扩展长度)
我们每到一个点,遍历n个初始点,看能否更新即可。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int dp[N];
int n,m;
struct ante {
	int len, pos;
}ant[100];
int main()
{
	n = read(), m = read();
	upd(i, 1, n)
	{
		ant[i].pos = read();
		ant[i].len = read();
	}
	upd(i, 1, m)dp[i] = 1e9;
	upd(i, 1, m)
	{
		dp[i] = i;
		upd(j, 1, n)
		{
			if (ant[j].pos - ant[j].len <= i && ant[j].pos + ant[j].len >= i)
			{
				dp[i] = min(dp[i], dp[max(0,ant[j].pos-ant[j].len-1)]);
			}
			else if (ant[j].pos - ant[j].len <= i)
			{
				dp[i] = min(dp[i], dp[max(0, 2 * ant[j].pos - i - 1)] + max(0,i - ant[j].pos - ant[j].len));
			}
		}
	}
	printf("%d\n", dp[m]);
	return 0;
}

F题:kruskal重构树/启发式合并+dij
首先我们令d[u]表示u节点到最近的加油站需要的油是多少。
因为从加油站出发到加油站。所以我们先假设从x到y,x和y都是加油站。
x到u花费为val,这个val一定大于等于d[u],当前剩余油量为c-val。我们假设c-val大于d[u],那么,如果u节点去最近的加油站加油后,再回来u节点,那么这个时候的剩余油量一定是大于等于c-val的。
我们进一步思考,从加油站出发到达加油站的整个过程中,如果剩余油量小于d[u],那么一定走不到下一个加油站,x>=d[u],然后,如果要从u节点走到邻接的节点v,需要花费wu-v,剩余油量x>=d[u]+w,走到v节点,v节点必须要满足x>=d[v],合起来当前剩余油量一定要大于等于d[v]+d[u]+wu-v即如果要从u节点走到v节点,剩余油量一定大于等于两个节点到最近的加油站加油并且通过改变的和。这是一个贪心出来的结果。我们每一次都去最近的地方加油,加油回来过后,当前剩余的油量至少不会减少,回来时候油量变为c-d[u],继续往下走急需要c-d[u]>=w+d[v],移项求得。
边权全部变成d[u]+d[v]+wuv
问题转变成为求两点至今,路径权值的最大最小值。使用kruskal重构树刚好满足该性质,当然使用启发式合并离线操作也是可行的,代码量也更小。
使用kruskal:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int n, m, k, q,cnt;
ll dis[2*N];
struct edge {
	int from,to, next;
	ll wi;
	bool operator<(const edge &node)const
	{
		return wi < node.wi;
	}
}edge[6*N];
int head[6 * N];
vector<int>tr[N << 1];
ll  tr_wi[N << 1];
int tr_num = 0;
void addedge(int u, int v,ll w)
{
	edge[cnt].from = u;
	edge[cnt].wi = w;
	edge[cnt].next = head[u];
	edge[cnt].to = v;
	head[u] = cnt++;
}
void dj()
{
	priority_queue<pair<ll,int>, vector<pair<ll,int> >, greater<pair<ll,int> > >que;
	upd(i, 1, n)
	{
		if (i <= k) {
			que.push(make_pair(0, i));
		}
		else dis[i] = 1e18;
	}
	while (!que.empty())
	{
		auto s = que.top(); que.pop();
		ll fi = s.first;
		int se = s.second;
		if (dis[se] < fi)continue;
		for (int i = head[se]; ~i; i = edge[i].next)
		{
			int v = edge[i].to;
			if (dis[v] > fi + edge[i].wi)
			{
				dis[v] = fi + edge[i].wi;
				que.push(make_pair( dis[edge[i].to], edge[i].to));
			}
		}
	}
}
int pr[N<<1],height[N<<1];
void init()
{
	upd(i, 0, (n << 1))
	{
		pr[i] = i;
		height[i] = 1;
	}
}
int find_pr(int f)
{
	return pr[f] == f ? f : pr[f] = find_pr(pr[f]);
}
void unit(int u, int v)
{
	u = find_pr(u);
	v = find_pr(v);
	if (u == v)return;
	if (height[u] < height[v])swap(u, v);
	pr[v] = u;
	height[u] += height[v];
}
bool same(int u, int v)
{
	return find_pr(u) == find_pr(v);
}
void ek_kruskal()
{
	tr_num = n;
	up(i, 0, cnt)
	{
		int u = edge[i].from;
		int v = edge[i].to;
		u = find_pr(u), v = find_pr(v);
		if (same(u, v))continue;
		else
		{
			ll w = edge[i].wi;
			tr_wi[++tr_num] = edge[i].wi;
			pr[u] = tr_num;
			pr[v] = tr_num;
			tr[tr_num].push_back(u); tr[tr_num].push_back(v);
		}
	}
}
int dep[2*N], fa[2*N][21];
void dfs(int u, int f,int d)
{
	dep[u] = d;
	fa[u][0] = f;
	for (int i = 1; i < 20 && fa[u][i - 1]; i++)
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
	for (auto k : tr[u])
	{
		dfs(k, u, d + 1);
	}
}
int lca(int u, int v)
{
	if (dep[u] < dep[v])swap(u, v);
	dwd(i, 19, 0)
		if (dep[fa[u][i]] >= dep[v])u = fa[u][i];
	if (u == v)return u;
	dwd(i, 19, 0)
		if (fa[u][i] != fa[v][i])
			u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
int main()
{
	memset(head, -1, sizeof(head));
	n = read(), m = read(), k = read(), q = read();
	int u, v; ll w;
	upd(i, 1, m)
	{
		u = read(), v = read(), w = read();
		addedge(u, v, w);
		addedge(v, u, w);
	}
	//up(i,0,cnt)
	//printf("%d\n", edge[i].from);
	dj();
	up(i, 0, cnt)
	{
		edge[i].wi += dis[edge[i].from] + dis[edge[i].to];
	}
	sort(edge, edge + cnt);
	init();
	ek_kruskal();
	dfs(tr_num, 0, 1);
	while (q--)
	{
		u = read(), v = read();
	//	cout << "lca" << lca(u, v) << endl;
		printf("%lld\n", tr_wi[lca(u, v)]);
	}
	return 0;
}

使用启发式合并:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#pragma GCC optimize(2)
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
	char ch = getchar(); ll x = 0, f = 1;
	while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
	return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 1e5 + 10;
int n, m, k, q,cnt;
ll dis[2*N];
struct edges {
	int from,to, next;
	ll wi;
	bool operator<(const edges &node)const
	{
		return wi < node.wi;
	}
}edge[6*N];
int head[6 * N];
vector<int>tr[N << 1];
ll  tr_wi[N << 1];
int tr_num = 0;
void addedge(int u, int v,ll w)
{
	edge[cnt].from = u;
	edge[cnt].wi = w;
	edge[cnt].next = head[u];
	edge[cnt].to = v;
	head[u] = cnt++;
}
void dj()
{
	priority_queue<pair<ll,int>, vector<pair<ll,int> >, greater<pair<ll,int> > >que;
	upd(i, 1, n)
	{
		if (i <= k) {
			que.push(make_pair(0, i));
		}
		else dis[i] = 1e18;
	}
	while (!que.empty())
	{
		auto s = que.top(); que.pop();
		ll fi = s.first;
		int se = s.second;
		if (dis[se] < fi)continue;
		for (int i = head[se]; ~i; i = edge[i].next)
		{
			int v = edge[i].to;
			if (dis[v] > fi + edge[i].wi)
			{
				dis[v] = fi + edge[i].wi;
				que.push(make_pair( dis[edge[i].to], edge[i].to));
			}
		}
	}
}
int pr[3 * N];
int height[3 * N];
set<int>s[3 * N];
ll ans[3*N];
vector<pir>ip[N];
void init()
{
	upd(i, 0, n)pr[i] = i, height[i] = 1,s[i].insert(i);
}
int find_pr(int u)
{
	return pr[u] == u ? u : pr[u] = find_pr(pr[u]);
}
bool same(int u, int v)
{
	return find_pr(u) == find_pr(v);
}
void insert(int u, int v,ll w)
{
	u = find_pr(u), v = find_pr(v);
	if (u == v)return;
	if (height[u] < height[v])swap(u, v);
	pr[v] = u; height[u] += height[v];
	for (auto k : s[v])for (auto p : ip[k])
	{
		if (s[u].count(p.second))ans[p.first] = w;
	}
	for (auto k : s[v])s[u].insert(k);
}
int main()
{
	memset(head, -1, sizeof(head));
	n = read(), m = read(), k = read(), q = read();
	int u, v; ll w;
	upd(i, 1, m)
	{
		u = read(), v = read(), w = read();
		addedge(u, v, w);
		addedge(v, u, w);
	}
	dj();
	up(i, 0, cnt)
	{
		edge[i].wi += dis[edge[i].from] + dis[edge[i].to];
	}
	sort(edge, edge + cnt);
	int ip_cnt=0;
	init();
	while (q--)
	{
		u = read(), v = read();
		ip[u].push_back(make_pair(ip_cnt, v));
		ip[v].push_back(make_pair(ip_cnt, u));
		ip_cnt++;
	}
	up(i, 0, cnt)
	{
		u = edge[i].from;
		v = edge[i].to;
		insert(u, v,edge[i].wi);
	}
	up(i, 0, ip_cnt)
	{
		printf("%lld\n", ans[i]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值