【超好懂的比赛题解】2021 年四川省大学生程序设计竞赛

这篇具有很好参考价值的文章主要介绍了【超好懂的比赛题解】2021 年四川省大学生程序设计竞赛。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


title : 2021 年四川省大学生程序设计竞赛
date : 2022-7-18
tags : ACM,练习记录
author : Linno


2021 年四川省大学生程序设计竞赛

题目链接:https://codeforces.com/gym/103117

进度:11/13

切题顺序:AKMBDHLJ

IF赛后补了,CG没看

A. Chuanpai

给定正整数 k,问有多少正整数对 (x, y) 满足 x + y = k 且 1 ≤ x ≤ y ≤ 6。

x 和 y 的可行范围很小,直接枚举即可。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
void Solve(){
	int n,ans=0;
	cin>>n;
	for(int i=1;i<=6;++i){
		for(int j=i;j<=6;++j){
			if(i+j==n) ans++;
		}
	}
	cout<<ans<<"\n";
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

B. Hotpot

n 个人围成一圈吃火锅。从第一个人开始轮流行动。每个人有且 仅有一种喜欢的食物。轮到一个人行动时,如果锅里有他喜欢的 食物,他就全吃光,他的快乐值 +1。否则,他就会往锅里下一 些他喜欢吃的食物,并结束行动。问所有人共行动 m 次后每个 人的快乐值。

注意到两轮过后集合中的肯定是没有元素的,以2n为一个周期统计答案,最后再直接暴力跑剩下的次数即可。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
int n,k,m,a[N],inq[N],cnt[N],ans[N];
void Solve(){
	memset(cnt,0,sizeof(cnt));
	memset(ans,0,sizeof(ans));
	memset(inq,0,sizeof(inq));
	cin>>n>>k>>m;
	for(int i=0;i<n;++i) cin>>a[i];
	for(int i=0;i<2*n;++i){  //计算两轮每个人的快乐数 
		if(inq[a[i%n]]){
			inq[a[i%n]]=0;
			++cnt[i%n];
		}else{
			inq[a[i%n]]=1;
		}
	}
	for(int i=0;i<n;++i){
		ans[i]+=m/(2*n)*cnt[i];
	}
	m%=(2*n);
	for(int i=0;i<m;++i){
		if(inq[a[i%n]]){
			inq[a[i%n]]=0;
			++ans[i%n];
		}else{
			inq[a[i%n]]=1;
		}	
	}
	for(int i=0;i<n;++i) cout<<ans[i]<<" \n"[i==n-1]; 
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

C. Triangle Pendant

有一个均匀的三角形薄片 ABC,三个顶点各有一条细线连到一 个点 D 上。给定三边的长度和三条细线的长度,问提起 D 让三 角形自然落下到稳定状态时,三个顶点距离 D 的垂直距离。

稳定状态下,三角形的重心位于 D 的正下方。 在三条线全拉直的情况下,计算三棱锥把重心旋转到 D 正 下方时 A, B, C 各自的坐标即可。 只能拉直一条线或两条线的答案比较好计算,但是要小心判 断什么时候会发生这两种情况。

不会写,没有代码。

D. Rock Paper Scissors

两个玩家各自有合计 n 张的剪刀、石头、布的牌,每一轮玩家 1 先打出一张剩余的牌,另一名玩家再打出一张剩余的牌,双方都 想最大化自己赢的局数减去输的局数。问最终后手的得分。

先手的决策没有意义,后手可以决定这 2n 张牌的匹配情况。 作为后手,只需要先尽量贪心匹配所有自己赢的 Pattern (如尽量把自己的石头匹配对方的剪刀),再匹配平局的 Pattern,再匹配输的 Pattern 即可。 具体证明可以借助费用流的思想。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline void read(ll &x) { //整型快读,注意这里是void有自变量
	x=0;
	char c=getchar();
	for (; !isdigit(c); c=getchar());
	for (; isdigit(c); c=getchar()) x=x*10+c-'0';
}
int main () {
	ll t;
	read(t);
	ll a[4],b[4];
	ll k[4][4];
	k[1][1]=0;
	k[1][2]=-1;
	k[1][3]=1;
	k[2][1]=1;
	k[2][2]=0;
	k[2][3]=-1;
	k[3][1]=-1;
	k[3][2]=1;
	k[3][3]=0;
	while(t--) {
		ll ans=0;
		for(int i=1; i<=3; ++i)
			read(a[i]);
		for(int i=1; i<=3; ++i)
			read(b[i]);
		if(b[1]>=a[3])
			b[1]-=a[3],ans+=a[3],a[3]=0;
		else a[3]-=b[1],ans+=b[1],b[1]=0;
		if(b[2]>=a[1])
			b[2]-=a[1],ans+=a[1],a[1]=0;
		else {
			a[1]-=b[2];
			ans+=b[2];
			b[2]=0;
		}
		if(b[3]>=a[2])
			b[3]-=a[2],ans+=a[2],a[2]=0;
		else {
			a[2]-=b[3];
			ans+=b[3];
			b[3]=0;
		}
		int cnt=0;
		int f=0;
		for(int i=1; i<=3; ++i) {
			if(a[i]==0)
				cnt++;
			else f=i;
		}
		if(cnt==3) {
			printf("%lld\n",ans);
		} else if(cnt==2) {
			for(int i=1; i<=3; ++i) {
				ans+=k[i][f]*b[i];
			}
			printf("%lld\n",ans);
		} else {
			for(int i=1; i<=3; ++i) {
				if(b[i]!=0) {
					f=i;
					break;
				}
			}
			for(int i=1; i<=3; ++i) {
				ans+=k[f][i]*a[i];
			}
			printf("%lld\n",ans);
		}
	}
	return 0;
}

E. Don’t Really Like How The Story Ends

给定一张无向图,问最少添加多少条边,可以使得 1, 2, · · · , n 是 这张图的一个合法 DFS 序列。

考虑什么时候不得不加边:如果在我们 dfs 的过程中走到了 i,并且不可能在下一步走到 i + 1,那么我们必须添加一条 边使得下一步能走到 i + 1。 这等价于在当前的 DFS 栈中,最深的一个有未访问邻居的 点与 i + 1 不相邻。 直接模拟这个过程即可。显然不按照这个过程加边不能使得 答案变得更优。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
vector<int>f[1000005];
int T,n,m,num,x,y,ans,cnt,visit[1000005];
struct dat
{
	int x,y;
}a[1000005];
bool cmp(dat a,dat b)
{
	if (a.x==b.x) return a.y<b.y;
	else return a.x<b.x;
}
void dfs(int x,int fa)
{
	visit[x]=1;
	if (x==n) return;
	int len=f[x].size();
	for (int i=0;i<len;++i)
	 if (!visit[f[x][i]])
	  if (f[x][i]==cnt+1) { cnt++; dfs(cnt,x);}
	  else { ans++; cnt++; dfs(cnt,x); i--; }
	while (x==1&&cnt!=n) { ans++; cnt++; dfs(cnt,x); }
}
int main()
{
	cin>>T;
	while (T--)
	 {
	 	scanf("%d%d",&n,&m);
	 	for (int i=1;i<=n;++i) 	
		  { 
		   visit[i]=0;
		   f[i].clear();
	}
		num=0;
		for (int i=1;i<=m;++i)
		 {
		 	scanf("%d%d",&x,&y);
		 	if (x==y) continue;
		 	if (x>y) swap(x,y); 
		 	a[++num]={x,y};
		 }
		sort(a+1,a+1+num,cmp);
		for (int i=1;i<=num;++i)
		 if (a[i].x!=a[i-1].x||a[i].y!=a[i-1].y) 
		  {
		  	f[a[i].x].push_back(a[i].y);
		  	f[a[i].y].push_back(a[i].x); 
		  }
		//for (int i=1;i<=n;++i) sort(f[i].begin(),f[i].end());
		ans=0; cnt=1;
		dfs(1,0);
		printf("%d\n",ans);
	 }
	return 0; 
}

F. Direction Setting

一个 n 个点 m 条边的无向图,每个点有一个权值 ai。要求给所 有边定向,令 di 表示定向后 i 号点的入度,要求最小化 D = ∑ i = 1 n m a x ( 0 , d i − a i ) D = \sum^n_{i=1} max(0, d_i − a_i) D=i=1nmax(0,diai)

很容易想到用最大流来解决,源点与每条边连上容量为1的边,那些边向对应端点连上容量为1的边,这样就可以表示每条边选择一个点,最后每个点向汇点连容量为a[i]的边,那么边数减去跑出来的最大流就是最小的D,然后直接根据每条边的方向输出即可。

#include<bits/stdc++.h>
#define int long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=2e5+7;

int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}

struct E{
	int u,v,w,nxt;
}e[N];
int head[N],cur[N],cnt=1;
inline void addedge(int f,int v,int w){
	e[++cnt]={f,v,w,head[f]};head[f]=cnt;
}

int n,m,s,t,a[N],mp[1005][1005],u[N],v[N],id[N],deg[N],ru[N];
int lv[N];

inline bool bfs(){ //BFS分层 
	memset(lv,-1,sizeof(lv)); 
	memcpy(cur,head,sizeof(head)); //初始化弧优化 
	queue<int>q;
	q.push(s);lv[s]=0;
	while(!q.empty()){
		int fro=q.front();
		q.pop();
		for(int i=head[fro];i;i=e[i].nxt){
			int to=e[i].v,dis=e[i].w;
			if(dis>0&&lv[to]==-1){
				lv[to]=lv[fro]+1;
				q.push(to);
				if(to==t) return true;
			}
		}
	}
	return false;
}

inline int dfs(int p=s,int flow=inf){
	if(p==t) return flow;
	int lft=flow; //剩余的流量 
	for(int i=cur[p];i&&lft;i=e[i].nxt){ //从当前弧开始出发 
		cur[p]=i; //更新当前弧
		int to=e[i].v,dis=e[i].w;
		if(dis>0&&lv[to]==lv[p]+1){ //向层数高的地方增广 
			int c=dfs(to,min(dis,lft)); //尽可能多地传递流量 
			lft-=c;  //更新剩余流量 
			e[i].w-=c; //更新残差流量 
			e[i^1].w+=c; // 
		}
	} 
	return flow-lft; //返回传递出去的流量大小 
}

int Dinic(){
	int ans=0;
	while(bfs()){
		ans+=dfs();
	}
	return ans;
}


void solve(){
	memset(mp,0,sizeof(mp));
	memset(ru,0,sizeof(ru));
	memset(head,0,sizeof(head));
	memset(cur,0,sizeof(cur));
	memset(id,0,sizeof(id));
	memset(deg,0,sizeof(deg));
	cnt=1;
	n=read();m=read();s=0;t=n+m+1;
	for(int i=1;i<=n;++i){  //读入 
		a[i]=read();
	}
	for(int i=1;i<=m;i++){
		u[i]=read();v[i]=read();
		addedge(s,n+i,1);
		addedge(n+i,s,0);
		addedge(n+i,u[i],1);
		addedge(u[i],n+i,0);
		addedge(n+i,v[i],1);
		id[i]=cnt; //记录id正向时的 
		addedge(v[i],n+i,0);
	}
	for(int i=1;i<=n;++i){
		addedge(i,t,a[i]);
		addedge(t,i,0);
	}
	printf("%lld\n",m-Dinic());  //总和-最大流 
	for(int i=1;i<=m;++i){
		int p=id[i];
		if(e[p].w<=0) putchar('0'); //说明这条边翻转了,直接用原边 
		else putchar('1');
	}
	putchar('\n');
}

signed main(){
	int T;
	T=read();
	while(T--){
		solve();
	}
	return 0;
}

G. Hourly Coding Problem

把一个长度为 n 的整数数组分成 k 个非空连续段。令各段内部 的和是 s1,s2, · · · ,sk,最小化 max(si)。要求输出最优方案中各段 的长度,如果有多组解,输出长度序列字典序最大者。

二分答案,二分值确定后合法的 k 是个区间,树状数组优化 dp 维护 [i,n] 最多最少能分成几块。 输出答案时前缀和值域线段树维护目前能够分成的块数合法 的下标(mini <= k <= maxi),每次是前缀查询最大值 + 新增/删除合法下标 (k 减小 1 后维护合法下标) 时间复杂度 O(n log n log( ∑ai))。

(不会写,没有代码)

H. Nihongo wa Muzukashii Desu

给定日语的一种动词变体规则,输出读入单词的变体

按照题意模拟即可。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
void Solve(){
	string str;
	cin>>str;
	int len=str.length();
	int st1=str.find("chimasu");
	int st2=str.find("rimasu");
	int st4=str.find("mimasu");
	int st5=str.find("bimasu");
	int st6=str.find("nimasu");
	int st7=str.find("ikimasu");
	int st8=str.find("kimasu");
	int st9=str.find("gimasu");
	int st10=str.find("shimasu");
	int st3=str.find("imasu");
//	cout<<len<<" "<<st1<<" "<<st2<<" "<<st3<<"!!\n";
	if(st1>=0&&st1<=len){
		for(int i=0;i<st1;++i){
			cout<<str[i];
		}
		cout<<"tte\n";
	}else if(st2>=0&&st2<=len){
		for(int i=0;i<st2;++i){
			cout<<str[i];
		}
		cout<<"tte\n";
	}else if(st4>=0&&st4<=len){
		for(int i=0;i<st4;++i){
			cout<<str[i];
		}
		cout<<"nde\n";
	}else if(st5>=0&&st5<=len){
		for(int i=0;i<st5;++i){
			cout<<str[i];
		}
		cout<<"nde\n";
	}else if(st6>=0&&st6<=len){
		for(int i=0;i<st6;++i){
			cout<<str[i];
		}
		cout<<"nde\n";
	}else if(str=="ikimasu"){
		cout<<"itte\n";
	}else if(st8>=0&&st8<=len){
		for(int i=0;i<st8;++i){
			cout<<str[i];
		}
		cout<<"ite\n";
	}else if(st9>=0&&st9<=len){
		for(int i=0;i<st9;++i){
			cout<<str[i];
		}
		cout<<"ide\n";
	}else if(st10>=0&&st10<=len){
		for(int i=0;i<st10;++i){
			cout<<str[i];
		}
		cout<<"shite\n";
	}else if(st3>=0&&st3<=len){
		for(int i=0;i<st3;++i){
			cout<<str[i];
		}
		cout<<"tte\n";
	}
}

signed main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

I. Monster Hunter

玩家的攻击力序列是 a1, a2, · · · , an 无限循环,有 m 只怪物的血 量是 h1, h2, · · · , hm。问击败所有怪物最少需要几次攻击。 1 ≤ n, m ≤ 100000, 1 ≤ ai ≤ 3。

二分答案,转变为有若干个大小为 1, 2, 3 之一的物体,问能 不能填满大小为 h1, h2, · · · , hm 的空间(可以溢出)。 如果没有 3 是一个简单的贪心,只要在不溢出的情况下尽量 放 2,如果还有剩余的 2 再往剩余空间为 1 的格子里放,最 后再放 1 即可。 有 3 的情况思想类似,就是尽量避免当前的浪费和之后过程 的浪费。 具体过程如下:先往剩余空间为大于等于 3 的奇数的位置放 一个 3;再往所有大于等于 6 的格子尽量多地放两个一组的 3。(尽量保持偶数可以减小放 2 和 1 时的浪费)。此时如果 恰好只有一个 3 剩余,就把它放到剩余的最大的格子里。之 后依次往剩余空间为 4, 2, 1 的格子放 3 即可。之后就转化为 了只有 1, 2 的贪心。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7;
struct dat {
	int one,two,thr;
} cnt[N];
int T,n,m,sum,a[N],b[N],c[N],s;
bool cmp(int a,int b) {
	return a>b;
}

bool check(int x) {
	for(int i=1;i<=m;++i) b[i]=c[i];		
	int k=x/n;
	int cnt1=cnt[n].one*k;
	int cnt2=cnt[n].two*k;
	int cnt3=cnt[n].thr*k;
	cnt1+=cnt[x%n].one;
	cnt2+=cnt[x%n].two;
	cnt3+=cnt[x%n].thr;
	if(cnt1+cnt2*2+cnt3*3<s) return false;
	for(int i=1;cnt3&&i<=m;++i){
		if(b[i]>=3){
			if (b[i]%2){
				cnt3--;
				b[i]-=3;
			}
		}
	}
	for(int i=m;cnt3&&i>=1;--i){
		if(b[i]>=6){
			int t=b[i]/6;
			if(t*2<=cnt3){
				b[i]-=6*t;
				cnt3-=2*t;
			}else{
				b[i]-=3*(cnt3-(cnt3&1));
				cnt3&=1;
			}
		}
	}
	sort(b+1,b+1+m,cmp);
	for(int i=1;cnt3&&i<=m;++i){
		if(b[i]!=0){
			cnt3--;
			b[i]=max(0ll,b[i]-3ll);
		}
	}
	for(int i=1;cnt3&&i<=m;++i){
		if(b[i]==2){
			b[i]=0;
			--cnt3;
		}
	}
	for(int i=1;cnt3&&i<=m;++i){
		if(b[i]!=0){
			b[i]=0;
			--cnt3;
		}
	}
	for(int i=1;cnt2&&i<=m;++i){
		if(b[i]>=2){
			if(cnt2*2>=b[i]){
				cnt2-=b[i]/2;
				b[i]%=2;
			}else{
				b[i]-=cnt2*2;
				cnt2=0;
				break;
			}
		}
	}
	for(int i=1;cnt2&&i<=m;++i){
		if(b[i]){
			cnt2--;
			b[i]=max(0ll,b[i]-2);
		}
	}
	int hpsum=0;
	for(int i=1;i<=m;++i)
		if (b[i]>0) hpsum+=b[i];
	if(cnt1>=hpsum) return true;
	else return false;

}
signed main(){
	scanf("%d",&T);
	while (T--) {
		scanf("%d",&n);
		sum=0;
		for (int i=0; i<=n; ++i) cnt[i].one=cnt[i].two=cnt[i].thr=0; //初始化 
		for (int i=1; i<=n; ++i) {
			scanf("%lld",&a[i]); 
			sum+=a[i];
			cnt[i]=cnt[i-1];
			if (a[i]==1) cnt[i].one++;
			else if (a[i]==2) cnt[i].two++;
			else cnt[i].thr++;
		}
		scanf("%d",&m);
		s=0;
		for (int i=1; i<=m; ++i) {
			scanf("%lld",&b[i]);
			s=s+b[i];
			c[i]=b[i];
		}
		sort(c+1,c+1+m,cmp);
		int l=0,r=s+1,mid=0;
		while (r-l>1) {  //二分 
			mid=((l+r)>>1);
			if (check(mid)) r=mid;
			else l=mid;
		}
		printf("%lld\n",r);
	}
	return 0;
}

J. Ants

长度 L = (1e9 + 1) 的数轴上 N 只蚂蚁,蚂蚁互相碰到之后各自转身,数轴两端各有一块挡板,一只蚂蚁撞到之后直接转身,挡板被撞 K 次就消失,问所有蚂蚁走出去的时间。

在挡板消失之前,每隔 2L 的的时间所有蚂蚁会回到初始状 态,每块挡板被碰撞 n 次。因此可以直接模拟最后一轮的状 态,这一轮中至多只碰撞 n 次。 蚂蚁的相对顺序不变。同时在算下一次碰撞时间时可以认为 未发生碰撞,直接穿过。 两块挡板都维护一个队列,维护撞到这块挡板的蚂蚁的时间 序列,每次在两个队头中选择一个最小值,模拟之后塞进另 一个队列即可。

#include<bits/stdc++.h>
#define int __int128
using namespace std;
typedef long long ll;
int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}

int a[1000005];
int d[10000005];
int tr[1000005];
int tl[1000005];

const int mod=1e9+1;
signed main (){
    int n,aa,bb;
    n=read();aa=read();bb=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
    }
    for(int i=1;i<=n;++i)
        d[i]=read();
    int cnt=0,cnt1=0;
    tl[0]=0;
    tr[0]=0;
    for(int i=1;i<=n;++i)
    {    
        if(d[i]==0)
         {
            tl[++cnt1]=a[i];
        }
    }
    for(int i=n;i>=1;--i)
    {
        if(d[i]==1)
        {
            tl[++cnt1]=(2ll*mod-a[i]);
            tr[++cnt]=(mod-a[i]);
        }
    }
    for(int i=1;i<=n;++i)
    {
        if(d[i]==0)
        {
            tr[++cnt]=a[i]+mod;
        }
    }
    int nn=n;
    int rallt,lallt;
    if(bb%nn!=0)
     rallt=(bb/(nn))*2ll*mod+tr[(bb-(bb/(nn))*nn)];
    else  rallt=((bb/(nn))-1)*2ll*mod+tr[nn];
        if(aa%nn!=0)
     lallt=(aa/(nn))*2ll*mod+tl[(aa-(aa/(nn))*nn)];
    else  lallt=((aa/(nn))-1)*2ll*mod+tl[nn];
    int ans=0;
    if(rallt>=lallt)
    {
        if(rallt>=lallt+mod)
        {
            ans=lallt+2*mod;
        }
        else {
            ans=rallt+mod;
        }
    }
    else {
        if(lallt>=rallt+mod)
            ans=rallt+2*mod;
        else ans=lallt+mod;
    }
    write(ans);putchar('\n');
    return 0;
}

K. K-skip Permutation

给定 n, k,构造一个 1 − n 的排列 p1, p2, · · · , pn,使得满足 pi + k = pi+1 的下标 i 最多。

将 MOD k 相同的值放在一起,从小到大依次输出。显然可 以达到理论最大值。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n,k,visit[1000005],f[1000006],num;
int main()
{
	cin>>n>>k;
	for (int i=1;i<=n;++i)
	 if (!visit[i]) 
	  {
	  	for (int j=i;j<=n;j+=k)
	  	 {
	  	 	f[++num]=j;
	  	 	visit[j]=1;
	  	 }
	  }
	printf("%d",f[1]);
	for (int i=2;i<=num;++i)
	 printf(" %d",f[i]);
	return 0;
}

L. Spicy Restaurant

无向图的每个顶点有一个属性 wi,Q 个询问,第 i 个询问给定顶 点 p 和阈值 a,问距离 p 最近的 wi ≤ a 的 i 距离 p 有多远。 1 ≤ wi ≤ 100。

w 的范围很小,直接做 100 次 BFS,计算出 d[i][j] 表示离 i 最近的属性值恰好为 j 的点的距离即可。时间复杂度 O(100(n + m) + Q)。

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
//#define int long long
#define mk make_pair
#define pii pair<int,int>
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
int n,m,q,w[N],dp[N][105],vis[N];
vector<int>G[N];
queue<pii>que[105];

void Solve(){
	cin>>n>>m>>q;
	memset(dp,inf,sizeof(dp));
	for(int i=1;i<=n;++i){
		cin>>w[i];
		dp[i][w[i]]=0;
		que[w[i]].push(mk(0,i));
	}
	for(int i=1,u,v;i<=m;++i){
		cin>>u>>v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	for(int i=0;i<=100;++i){
		memset(vis,0,sizeof(vis));
		while(que[i].size()){
			int fro=que[i].front().second;
			int w=que[i].front().first;
			que[i].pop();
			vis[fro]=0;
			for(auto to:G[fro]){
				if(dp[to][i]>w+1){
					dp[to][i]=w+1;
					if(!vis[to]){
						vis[to]=1;
						que[i].push(mk(dp[to][i],to));
					}
				}
			}
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=0;j<=99;++j){
			dp[i][j+1]=min(dp[i][j+1],dp[i][j]);
		}
	}
	for(int i=1,p,a;i<=q;++i){
		cin>>p>>a;
		if(dp[p][a]>=inf) cout<<-1<<"\n";
		else cout<<dp[p][a]<<"\n";
	}
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
//	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

M. True Story

有 n 个旅客在位置 0 同时出发赶飞机,飞机的位置是 x。第 i 个 人以 si 的速度匀速运动。初始时,飞机预定在时刻 p0 起飞。有 m 个广播,第 i 个广播在 ti 时刻告诉所有旅客飞机延误到了 pi, 保证 ti 和 pi 是递增的。每个旅客在每个时刻都会根据当前自己 的位置、当前自己的速度和当前预定的起飞时间来决定行动:如 果赶得上飞机就继续移动,否则就原地停留。问最终有多少个旅 客赶得上飞机。

注意到 pi 是递增的,因此一个旅客开始移动后就一定会到 达终点。 判断一个旅客 j 是否会开始移动,相当于判断是否存在一个 i,使得 sj ∗ (pi − ti) ≥ x。因此可以由最大的 pi − ti 判断。 找到最大的 pi − ti(令 t0 = 0),依次判断每一个旅客能否在 maxi (pi − ti) 的时间里走完 x 的距离即可。 时间复杂度 O(n + m)。文章来源地址https://www.toymoban.com/news/detail-451257.html

//#pragma GCC optimize("Ofast", "inline", "-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
const int N=2e5+7;
const int mod=1e9+7;

//int read(){	int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=f*-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}
//void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
int n,k,x,s[N],t[N],p[N],mx,ans=0;
void Solve(){
	cin>>n>>k>>x>>mx;
	for(int i=1;i<=n;++i) cin>>s[i];
	for(int i=1;i<=k;++i) cin>>t[i];
	for(int i=1;i<=k;++i){
		cin>>p[i];
		p[i]-=t[i];
		mx=max(mx,p[i]);
	}
	for(int i=1;i<=n;++i) if(s[i]*mx>=x) ++ans;
	cout<<ans<<"\n"; 
}

signed main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0);cout.tie(0);
//  freopen("in.cpp","r",stdin);
//  freopen("out.cpp","w",stdout);
	int T=1;
//	cin>>T;
//	clock_t start,finish;
//	start=clock();
	while(T--){
		Solve();
	}
//	finish=clock();
//	cerr<<((double)finish-start)/CLOCKS_PER_SEC<<endl;
	return 0;
}

到了这里,关于【超好懂的比赛题解】2021 年四川省大学生程序设计竞赛的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023 年四川省职业院校技能大赛(高等职业教育) “信息安全管理与评估”样题

    竞赛需要完成三个阶段的任务,分别完成三个模块,总分共计 1000分。三个模块内容和分值分别是: 1.第一阶段:模块一 网络平台搭建与设备安全防护(180 分钟,300 分)。 2.第二阶段:模块二 网络安全事件响应、数字取证调查、应用程序安全(180 分钟,300 分)。 3.第三阶

    2024年02月07日
    浏览(51)
  • sakuya726's 2023 ICPC China SiChuan Provincial Programming Contest(ICPC2023四川省赛)游记随笔

    出发前一天,收拾东西做好准备工作。打印了自己记忆中所有高级数据结构的板子(然而实际上并没有卵用),VP一把往年的四川省赛。 不出意外的失眠了,早上九点四十的火车,凌晨五点才睡觉。七点半出发去火车站,天还下着雨,刚开始感觉还挺有意境,然后当我在雨中

    2024年02月07日
    浏览(64)
  • 湘大 XTU OJ 1308 比赛 题解:循环结束的临界点+朴素模拟

    比赛 有 n个人要进行比赛 ,比赛规则如下: 假设每轮比赛的人是m,取 最大的k , k=2^t 且k≤m。 这k个人每2人举行一场比赛 ,胜利者进入一下轮,失败者被淘汰。 余下的m-k个人,不进行比赛,直接进入下一轮 直到决出冠军,比赛结束 。 比如有5个人参加比赛,第一轮举办

    2024年02月13日
    浏览(40)
  • 2021第六届数维杯大学生数学建模竞赛赛题_C 运动会优化比赛模式探索

    运动会优化比赛模式探索 5月中旬恰好是各个大学召开每年一届的运动的时间节点。运动会已成为了大学校园里一道亮丽的风景线,运动会上振奋人心的开幕式、拍手称赞的比赛、激动人心的颁奖仪式都给参加运动会的同学们带来了一次精神上的享受。每一次运动会举办的过

    2023年04月13日
    浏览(54)
  • 2021 RoboCom 世界机器人开发者大赛-本科组(决赛)题解

    市政规划了一块绿地,需要采购一批围栏将绿地围起来。 为了简单起见,我们假设绿地的形状是个封闭连通的规则多边形,即所有边都是互相垂直或平行的,并且没有交叉的十字边。我们指定某条垂直边上的一个点为原点 (0,0),然后按照顺时针记录这个多边形的拐角顶点的位

    2024年02月14日
    浏览(40)
  • 【Java】2021 RoboCom 机器人开发者大赛-高职组(初赛)题解

    机器人小白要来 RoboCom 参赛了,在赛场中遇到人要打个招呼。请你帮它设置好打招呼的这句话:“ni ye lai can jia RoboCom a?”。 输入格式: 本题没有输入。 输出格式: 在一行中输出 ni ye lai can jia RoboCom a? 。 输入样例: 输出样例: Solution: 人脸识别是基于人的脸部特征信息进

    2024年02月12日
    浏览(39)
  • 【Java】2021 RoboCom 机器人开发者大赛-高职组(复赛)题解

    号称具有人工智能的机器人,至少应该能分辨出新人和老朋友,所以打招呼的时候应该能有所区别。本题就请你为这个人工智能机器人实现这个功能:当它遇到陌生人的时候,会说:“Hello X, how are you?”其中 X 是这个人的称呼;而当它再次遇到这个人的时候,会说:“Hi X!

    2024年02月12日
    浏览(40)
  • 2021 第十二届蓝桥杯大赛软件赛省赛,C/C++ 大学B组题解

    序 比赛时长: 四个小时 比赛规则: 蓝桥杯比赛跟天梯赛、ACM还不太一样,比赛中提交的答案并没有反馈机制,也就是说你提交了答案以后,自己并不知道是对是错,就像考试一样,只有交了卷,成绩下来以后才能知道自己的奖项。 满分150 T1-T5答案提交共45分,分值分别是

    2023年04月09日
    浏览(44)
  • 【Xgplayer】xgplayer基本使用 | xgplayer使用 | 超好的前端视频播放器 | xgplayer前端最好视频播放器

    开发团队——字节跳动,字节跳动出品,必属精品。 xgplayer是一个超级牛逼的前端视频播放器,以下几个观点足以证明它的强大 大厂出品——稳 简洁 实用 优雅 文档清晰明了 支持弹幕 对移动端非常友好 自定义插件方便且强大 强就是了 xgplayer官网-点我进入 备用地址 https:

    2024年02月06日
    浏览(76)
  • 爱尔四川眼科医院—四川大学华西联盟医院隆重揭牌

    为积极响应国家“健康中国”“创新发展”战略,全面深化“产教融合”、“校企合作”、“医工融合”,推动“名校+名企” 双赢合作,提升中国眼科领域人才核心竞争力,继2021年9月23日四川大学与爱尔眼科战略合作签约后,2023年7月11日,“ 爱尔四川眼科医院—四川大学

    2024年02月15日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包