2022-05-04定时训练

32 篇文章 1 订阅

好耶~又是炸裂的一天

首先这次的题目难度其实中肯,T1水,T2考思维,T3大模拟,T4小清新图论,T5***。

T1 镜像字符串

它的题面

然后你就可以发现它是一道水题了……

但是存在一个细节,就是当且仅当:

第一个字符与第二个字符相同,直接输出两次第一个字符。

否则遇见相同情况继续循环遍历,证明如下:

于是就可以愉快地敲代码了……

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int num=0,ch=0;
	char c=getchar();
	while(!isdigit(c))ch|=(c=='-'),c=getchar();
	while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=getchar();
	return ch?-num:num;
}
inline void write(int x){
	if(x>=10)write(x/10);
	if(x<0)x=-x,putchar('-');
	putchar(x%10+'0');
	return;
}
int T,n,cnt;
char s[100005],s1[100005];
signed main(){
//	freopen("mirror.in","r",stdin);
//	freopen("mirror.out","w",stdout);
	T=read();
	while(T--){
		cnt=0;
		scanf("%d %s",&n,s);
		if(s[0]==s[1]){
			printf("%c%c\n",s[0],s[0]);
			continue;
		}
		bool flag=0;
		for(int i=1;i<n;++i){
			if(s[i-1]<s[i]){
				for(int j=0;j<i;++j)printf("%c",s[j]);
				for(int j=i-1;j+1;--j)printf("%c",s[j]);
				puts("");
				flag=1;
				break;
			}
		} 
		if(!flag){
			for(int i=0;i<n;++i)printf("%c",s[i]);
			for(int i=n-1;i+1;--i)printf("%c",s[i]);
			puts("");
		}
	}
	return 0;
} 

T2 双端队列

题面:


题目描述

S h e r r y Sherry Sherry 现在碰到了一个棘手的问题,有 N N N 个整数需要排序。

S h e r r y Sherry Sherry 手头能用的工具就是若干个双端队列。

她需要依次处理这 N N N 个数,对于每个数, S h e r r y Sherry Sherry 能做以下两件事:

  1. 新建一个双端队列,并将当前数作为这个队列中的唯一的数;
  2. 将当前数放入已有的队列的头之前或者尾之后。

对所有的数处理完成之后, S h e r r y Sherry Sherry 将这些队列排序后就可以得到一个非降的序列。

输入格式

第一行包含一个整数 N N N,表示整数的个数。接下来的 N N N 行每行包含一个整数 D i D_i Di,其中 D i D_i Di 表示所需处理的整数。

输出格式

其中只包含一行,为 S h e r r y Sherry Sherry 最少需要的双端队列数。

样例

样例输入
6
3
6
0
9
6
3
样例输出
2

首先这是一道思维题,我们首先将元素标个号之后进行排序,然后容易发现以下性质:
任意队列 i d id id(即预处理标号的变化趋势,按照排序后遍历),总会有 i d id id 先降后升。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int num=0,ch=0;
	char c=getchar();
	while(!isdigit(c))ch|=(c=='-'),c=getchar();
	while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=getchar();
	return ch?-num:num;
}
inline void write(int x){
	if(x>=10)write(x/10);
	if(x<0)x=-x,putchar('-');
	putchar(x%10+'0');
	return;
}
int n,loc,_loc=1,tmp,Min=1145141919810,Max=-1145141919810,ans=1;
struct Q{
	int num,id;
}a[200005];
inline bool cmp(Q x,Q y){return x.num==y.num?x.id<y.id:x.num<y.num;}
signed main(){
//	freopen("queue.in","r",stdin);
//	freopen("queue.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i)a[i].num=read(),a[i].id=i;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;++i){
		if(a[i].num!=a[i+1].num){
			loc=i;
			if(!tmp){
				if(a[loc].id<=Min){
					Min=a[_loc].id;
				}else{
					tmp^=1;
					Max=a[loc].id;
				}
			}else{
				if(a[_loc].id>=Max){
					Max=a[loc].id;
				}else{
					++ans;
					tmp^=1;
					Min=a[_loc].id;
				}
			}
			_loc=i+1;
		}
	}
	write(ans);
	return 0;
} 

T3 时间复杂度

纯模拟,没有什么好说的,注意细节(所以你就可以看见我花花绿绿的分数)。

……

T4 软件安装

强连通分量+缩点+树形DP

题面

强连通分量跑几遍 Tarjan 就不必多说了,缩点也可以用 并查集,主要是为了处理环的情况,最后跑一遍 DP.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int num=0,ch=0;
	char c=getchar();
	while(!isdigit(c))ch|=(c=='-'),c=getchar();
	while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=getchar();
	return ch?-num:num;
}
inline void write(int x){
	if(x>=10)write(x/10);
	if(x<0)x=-x,putchar('-');
	putchar(x%10+'0');
	return;
}
int n,m,w[105],v[105],Dfn[105],per[105],low[105],cnt,ret,dp[105][505],CR[105],siz[105],MJL[105];
struct Q{
	int W,V;
}a[105];
vector<int>G[105],G1[105];
stack<int>s;
inline void dfs(int x){
	Dfn[x]=low[x]=++cnt,s.push(x);
	for(int i=0;i<G[x].size();++i){
		if(!Dfn[G[x][i]]){
			dfs(G[x][i]);
			low[x]=min(low[x],low[G[x][i]]);
		}else if(!per[G[x][i]]){
			low[x]=min(low[x],Dfn[G[x][i]]);
		}
	}
	if(low[x]==Dfn[x]){
		++ret;
		while(1){
			int tmp=s.top();s.pop();
			per[tmp]=ret;
			a[ret].V+=v[tmp];
			a[ret].W+=w[tmp];
			if(tmp==x)break; 
		}
	}
	return;
} 
inline void Dfs(int x){
	MJL[++MJL[0]]=x;
	for(int i=0;i<G1[x].size();++i){
		Dfs(G1[x][i]);
		siz[x]+=siz[G1[x][i]];
	}
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i)w[i]=read();
	for(int i=1;i<=n;++i)v[i]=read();
	for(int i=1;i<=n;++i){
		int x=read();
		G[x].push_back(i);
	}
	for(int i=1;i<=n;++i){
		if(!Dfn[i]){
			dfs(i);
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=0;j<G[i].size();++j){
			if(per[i]!=per[G[i][j]]){
				G1[per[i]].push_back(per[G[i][j]]);
				++CR[per[G[i][j]]];
			}	
		}
	}
	for(int i=1;i<=ret;++i){
		if(!CR[i]){
			G1[0].push_back(i);
		}
		siz[i]=1;
	}
	siz[0]=1;
	Dfs(0);
	for(int i=ret+1;i;--i){
		for(int j=1;j<=m;++j){
			dp[i][j]=dp[i+siz[MJL[i]]][j];
			if(j>=a[MJL[i]].W)dp[i][j]=max(dp[i][j],dp[i+1][j-a[MJL[i]].W]+a[MJL[i]].V);
		}
	}
	write(dp[1][m]);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值