ARC080简要题解

赛中3题,第四题想了个七七八八,但是还是差一点,最后膜了题解,赛后写过去的qwq。
在这里插入图片描述
没啥罚时,海星,不过T3的ST表写的很痛苦,感觉得多打打ST表板子了,这个推了我好一会。

C题:
分三种情况 4的倍数 2的倍数但不是4的倍数 奇数。
第二种显然打堆处理,可以整体看做一个奇数(如果有的话)
然后判一判。

#include<bits/stdc++.h>
using namespace std;
int n, m;
int val;
int cnt1, cnt2, cnt4;
int main() { 
	scanf("%d", &n);
	for(int i=1;i<=n;++i) { 
		scanf("%d", &val);
		if(val % 4 == 0) 
			cnt4++;
		else if(val % 2 == 0) 
			cnt2++;
		else
			cnt1++;
	} 
	if(cnt2) 
		cnt1++;
	printf(cnt4 - cnt1 >= -1 ? "Yes" : "No");
	return 0;
} 

D题:
给格子蛇形编个号,顺着涂就完事。

#include<bits/stdc++.h>
using namespace std;
int mp[120][120];
int x[10010], y[10010];
int h, w, n;
int a[10010], mcnt, pcnt;
int main() { 
	scanf("%d%d", &h, &w);
	for(int i=1;i<=h;++i) { 
		if(i % 2) 
			for(int j=1;j<=w;++j) 
				++mcnt, x[mcnt] = i, y[mcnt] = j;
			
		else 
			for(int j=w;j>=1;--j)
				++mcnt, x[mcnt] = i, y[mcnt] = j;
	} 
	scanf("%d", &n);
	for(int i=1;i<=n;++i) { 
		scanf("%d", &a[i]);
		for(int t=1;t<=a[i];++t) { 
			pcnt++;
			mp[x[pcnt]][y[pcnt]] = i;
		}
 	} 
 	for(int i=1;i<=h;++i) { 
 		for(int j=1;j<=w;++j) { 
 			printf("%d ",mp[i][j]);
 		} 
 		printf("\n");
 	} 
	return 0;
} 

E题:
好题。
字典序直接指向无脑贪心。
相邻且往后放,转化一下,变成任取往前放。
对于区间 [ l , r ] [l, r] [l,r],贪心的找从里面拿出的合法的字典序最小的pair是个啥。由于字典序最小,那么先第一位最小,然后第二位。
发觉左边是距离 l l l为偶数的下标的最小值,右边元素是在左边元素右边,距离 l l l为奇数下标的最小值。
下标奇偶限制是手玩出来的www,不然会发觉左边剩了奇数个元素,在原问题就没啥救。
然后变为区间奇偶下标查最值——俩st表。
查出来之后,本来想的是挂个三叉树,然后跑树上最小字典序的拓扑序,后来发觉我直接摸个堆出来就完事。
主要是ST表那里调了好一会,感觉对这东西确实不太熟。
(诶不过我脑补的ST表居然过了,就很开心.jpg)

#include<bits/stdc++.h>
using namespace std;
int stj[200010][20];
int sto[200010][20];
int lo[200010];
int mp[200010];
int pw[210];
int a[200010];
int n;

struct info { 
	int x, y;
	int lpos, rpos;
	int l, r;
	bool operator < (const info &a) const { 
		return x > a.x;
	} 
};
priority_queue<info>sth;

void init() { 
	pw[0] = 1;
	for(int i=1;i<=100;++i) 
		pw[i] = pw[i-1] * 2;
	for(int i=1;i<=n;++i) { 
		for(int j=0;j<=20;++j) { 
			if(pw[j] > i) { 
				lo[i] = j-1;
				break;
			} 
		} 
	} 
	for(int i=1;i<=n;++i) { 
		if(i % 2) 
			stj[i][0] = a[i], sto[i][0] = 0x3f3f3f3f;
		else
			sto[i][0] = a[i], stj[i][0] = 0x3f3f3f3f;
	} 
	
	for(int T=1;T<=19;++T) { 
		for(int i=1;i<=n;++i) { 
			int lef = i, rig = i + pw[T] - 1;
			int haf = i + pw[T-1];
			if(haf > n) { 
				sto[i][T] = sto[i][T-1];
				stj[i][T] = stj[i][T-1];
			} 
			else { 
				sto[i][T] = min(sto[i][T-1], sto[haf][T-1]);
				stj[i][T] = min(stj[i][T-1], stj[haf][T-1]);
			} 
		} 
	} 
	return;
} 

int query(int l, int r, bool type) { 
	//type = 0 sto          type = 1 stj
	int len = r - l + 1;
	int T = lo[len];
	int haf = r - pw[T] + 1;
	if(type == 1) 
		return min(stj[l][T], stj[haf][T]);
	else
		return min(sto[l][T], sto[haf][T]);
} 

info getpac(int l, int r) { 
	if(r < l) 
		return {0, 0, 0, 0, 0, 0};
	int ltar, rtar, lpos, rpos;
	if(l % 2 == 1) { 
		ltar = query(l, r, 1);
		lpos = mp[ltar];
		rtar = query(lpos+1, r, 0);
		rpos = mp[rtar];
	} 
	else { 
		ltar = query(l, r, 0);
		lpos = mp[ltar];
		rtar = query(lpos+1, r, 1);
		rpos = mp[rtar];
	} 
	return (info){ltar, rtar, lpos, rpos, l, r};
} 

void split(info a) { 
	int l = a.l, r = a.r, lpos = a.lpos, rpos = a.rpos;
	info nw;
	if(l < lpos-1) {
		nw = getpac(l, lpos-1);
		sth.push(nw);
	} 
	if(lpos+1 < rpos-1) { 
		nw = getpac(lpos+1, rpos-1);
		sth.push(nw);
	} 
	if(rpos+1 < r) {
		nw = getpac(rpos+1, r);
		sth.push(nw);
	} 
	return;
} 

int main() { 
	scanf("%d", &n);
	for(int i=1;i<=n;++i) 
		scanf("%d", &a[i]), mp[a[i]] = i;
	init();
	sth.push(getpac(1, n));
	while(!sth.empty()) { 
		info nw = sth.top(); sth.pop();
		printf("%d %d ", nw.x, nw.y);
		split(nw);
	} 
	return 0;
} 

F题:
首先看到区间反转,无脑转差分。
转了之后变成两点的翻转,且距离为奇质数。
然后是,如果俩数正好差一个奇质数,那么贡献为1,这里可以筛个质数然后跑二分图匹配。
然后就卡这儿了,卡了几分钟,后去膜了发题解。

题解爸爸告诉我,差偶数的话,差2可以5-3,差4可以7-3,差更多可以 哥 德 巴 赫 猜 想
谁没事想得起这玩意啊!
然后差奇数就可以变偶数 - 奇质数了,贡献3。
跑二分图匹配,剩下的贪一下。
哦对,注意二分图匹配的时候,与S相连的边和与T相连的边一定只能连单向边。要是偷懒,连双向,就会GG。
我也不知道他咋GG的,但是我G了。
dinic是贴的板。

#include<bits/stdc++.h>
using namespace std;
bool vis[10000040];
int prime[2000010];
int x[1010], y[1010];
int n, m;
const int maxn = 10000010;
int prcnt;

namespace Maxflow {
	struct edge {
		int to,flow,op;
	}; vector<edge>ed[10010];
	int ly[10010],cur[10010]; queue<int>sth;
	int SS, TT, pcnt;
	inline void ade(int l,int r,int f) {
		ed[l].push_back({r,f, (int)ed[r].size()});
		ed[r].push_back({l,0, (int)ed[l].size() - 1});
	}
	inline bool bfs(int S, int T) {
		memset(cur,0,sizeof(cur)),memset(ly,0,sizeof(ly)), ly[S] = 1, sth.push(S);
		while(!sth.empty()) { int nw = sth.front(); sth.pop();
			for(int i=0;i<ed[nw].size();++i) {
				int tar = ed[nw][i].to;
				if(ed[nw][i].flow == 0 || ly[tar]) continue;
				ly[tar] = ly[nw] + 1, sth.push(tar);
			}
		} return ly[T] != 0;
	}
	inline int dfs(int nw, int ftar, int nflow) {
		if(nw == ftar) return nflow;
		int ret = 0;
		for(int i=cur[nw];i<ed[nw].size();++i) { cur[nw] = i;
			int tar = ed[nw][i].to;
			if(ly[tar] != ly[nw] + 1) continue;
			int ncanf = dfs(tar, ftar, min(nflow - ret, ed[nw][i].flow));
			ed[nw][i].flow -= ncanf, ed[tar][ed[nw][i].op].flow += ncanf;
			ret += ncanf; if(ret == nflow) break;
		} return ret;
	}
	inline long long dinic(int S, int T) { long long ret = 0;
		while(bfs(S,T))
			ret += dfs(S,T,0x3f3f3f3f);
		return ret;
	}
} using namespace Maxflow;

void shai() { 
	for(int i=2;i<=maxn;++i) { 
		if(!vis[i])
			prime[++prcnt] = i;
		for(int j=1;i*prime[j] <= maxn;++j) { 
			vis[i*prime[j]] = 1;
			if(i % prime[j] == 0)
				break;
		} 
 	} 
 	vis[2] = 1;
 	vis[1] = 1;
} 

void solve() { 
	int jcnt = 0, ocnt = 0;
	SS = 1001, TT = 1002;
	// 奇数左边 偶数右边
	for(int i=1;i<=n;++i) { 
		if(x[i] % 2 == 1) 
			jcnt++, ade(SS, i, 1);
		else
			ocnt++, ade(i, TT, 1);
		
		for(int j=i+1;j<=n;++j) { 
			if(!vis[x[j] - x[i]]) { 
				if(x[j] % 2 == 1)
					ade(j, i, 1);
				else
					ade(i, j, 1);
			} 
		} 
	} 
	int bas = dinic(SS, TT);
	jcnt -= bas, ocnt -= bas;
	int ans = bas;
	ans += (jcnt / 2) * 2, jcnt = jcnt % 2;
	ans += (ocnt / 2) * 2, ocnt = ocnt % 2;
	if(jcnt + ocnt != 0)
		ans += 3;
	cout<<ans;
	return;
} 

int main() { 
	shai();
	scanf("%d", &m);
	for(int i=1;i<=m;++i) 
		scanf("%d", &y[i]);
	x[++n] = y[1];
	for(int i=2;i<=m;++i) { 
		if(y[i] != y[i-1] + 1) { 
			x[++n] = y[i-1] + 1;
			x[++n] = y[i];
		} 
	} 
	x[++n] = y[m] + 1;
//	for(int i=1;i<=n;++i) 
//		printf("%d ",x[i]);
//	printf("\n");
	solve();
	return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值