zzu2024三月招新(A-F,I-L)

目录

1.A

 2.B

3.C

4.D

5.E

6.F

7.I

8.J

9.K

10.L


先吐槽一波,比赛的dev超级难用,没有编辑错误提示,不能复制样例,太草了,开局还开错题了,第一个小时没出题,还好后面写了几个签到,最后出了7题.

1.A

这题n比较小,只有1e3,可以n方暴力过,稍大一点就很难了.具体来说就是枚举每个位置作为左端点,然后取两个值作为最大值ma,和最小值cma,往右边遍历加一个值,容易想到有三种情况:

如果大于ma,则更新为现在的最大值,原来的最大值变成次大值,如果处于ma和cma之间,则原来的次大值更新为这个数,原来的最大值不变,如果小于cma,则无任何变化

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n;
	cin>>n;
	vector<int>a(n+5);
	for(int i=1;i<=n;i++)cin>>a[i];
	int ci,zu,ans=0;
	for(int i=1;i<=n;i++)
	{
		ci=min(a[i],a[i+1]);
		zu=max(a[i],a[i+1]);
		ans+=ci;
		for(int j=i+2;j<=n;j++)
		{
			if(a[j]>zu)
			{
				ci=zu;
				zu=a[j];
				ans+=ci;
			}
			else if(a[j]<zu&&a[j]>ci)
			{
				ci=a[j];
				ans+=ci;
			}
			else if(a[j]<ci)
			{
				ans+=ci;
			}
		}
	}
	cout<<ans;
	return 0;
}



 2.B

这题是压轴题,容易想到最短路,而求"最大值的最小值"就很二分答案了,所以每试一个x,就检查这个x是否能跑出一个满足a[i]<=x的最短路且不超时,然后根据二分的套路"最小化"答案就行,但不知道为什么二分这个点集的体力数组会wa,如果有人知道,请教教我!这里也贴一个可以ac的代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
 
const int N = 1e4 + 10;
int a[N];
 
struct edge {
    int v, w;
};
vector<edge> e[N];
int n, m, st, ed, h;
int d[N];
int vis[N];
bool check(int x) {
    for (int i = 0; i <= n; i++) {
        d[i] = 1e18;
        vis[i] = 0;
    }
    priority_queue<pair<int,int>> q;
    q.push({0, st});
    d[st] = 0;
 
    if (a[st] > x) return false;
 
    while (!q.empty()) {
        auto now = q.top();
        q.pop();
        int u = now.second;
        if (vis[u]) continue;
        vis[u] = 1;
        for (auto t: e[u]) {
            int v = t.v, w = t.w;
            if (d[v] > d[u] + w && a[v] <= x) {
                d[v] = d[u] + w;
                q.push({-d[v], v});
            }
        }
    }
 
    return d[ed] <= h;
}
int bfind()
{
    int l = 0, r = 1e7 + 5;
    while (l+1 < r) {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid;
    }
    return r;
}
signed main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin >> n >> m >> st >> ed >> h;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    
    for (int i = 1; i <= m; i++) {
        int u, v, w; cin >> u >> v >> w;
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    int ans=bfind();
    if (ans == 1e7 + 5) cout << -1 << '\n';
    else cout << ans << '\n';
    return 0;
}

3.C

这题就纯模拟题了,就是代码要写的比较长,没啥思维难度

#include<bits/stdc++.h>
using namespace std;
#define int long long
string mp[5005];
map<char,pair<int,int>>mmp;
map<pair<int,int>,pair<int,int>>p;
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>mp[i];
		mp[i]=' '+mp[i];
	}
	int stx,sty;
	cin>>stx>>sty;
	int l;
	cin>>l;
	string s;
	cin>>s;
	//怎么解决传送
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(isalpha(mp[i][j]))
			{
				if(mmp.find( mp[i][j] )!=mmp.end())
				{
					p[mmp[mp[i][j]]]={i,j};
					p[{i,j}]=mmp[mp[i][j]]; 
				}
				else
				{
					mmp[ mp[i][j] ]={i,j};
				}
			}
		}
	}
	int x=stx,y=sty;
	//cout<<x<<" "<<y<<"\n"; 
	for(int i=0;i<s.size();i++)
	{
		int fx,fy;
		if(s[i]=='R')
		{
			 fx=x,fy=y+1;
		}
		else if(s[i]=='L')
		{
			 fx=x,fy=y-1;
		}
		else if(s[i]=='D')
		{
			 fx=x+1,fy=y;
		}
		else if(s[i]=='U')
		{
			 fx=x-1,fy=y;
		}
		if(fx<1||fx>n||fy<1||fy>m||mp[fx][fy]=='#')
			{
				//cout<<x<<" "<<y<<"\n";
				continue;
			}
		if(p.find({fx,fy})!=p.end())//发现传送阵 
		{
			x=p[{fx,fy}].first;
			y=p[{fx,fy}].second;
		} 
		else
		{
			x=fx;
			y=fy;
		}
		//cout<<x<<" "<<y<<"\n";
	}
	cout<<x<<" "<<y;
	return 0;
}



4.D

这题是bfs最短路板题,就不多说了

#include<bits/stdc++.h>
using namespace std;
//#define int long long
string mp[5005];
bool vis[5005][5005];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
int step[5005][5005];
map<char,pair<int,int>>mmp;
map<pair<int,int>,pair<int,int>>p;
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	memset(step,0x3f,sizeof(step));
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>mp[i];
		mp[i]=' '+mp[i];
	}
	//怎么解决传送
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(isalpha(mp[i][j]))
			{
				if(mmp.find( mp[i][j] )!=mmp.end())
				{
					p[mmp[mp[i][j]]]={i,j};
					p[{i,j}]=mmp[mp[i][j]]; 
				}
				else
				{
					mmp[ mp[i][j] ]={i,j};
				}
			}
		}
	}
	//bfs
	int x1,y1,x2,y2;
	cin>>x1>>y1>>x2>>y2;
	queue<pair<int,int>>q;
	step[x1][y1]=0;
	q.push({x1,y1});
	//vis[x1][y1]=true;
	while(!q.empty())
	{
		auto t=q.front();q.pop();
		int x=t.first,y=t.second;
		if(vis[x][y])continue;
		vis[x][y]=1;
		if(x==x2&&y==y2)
		{
			break;
		}
		for(int i=0;i<4;i++)
		{
			int fx=x+dx[i],fy=y+dy[i];
			if(fx<1||fx>n||fy<1||fy>m||mp[fx][fy]=='#'||vis[fx][fy])
			continue;
			if(p.find({fx,fy})!=p.end())
			{
				int tx=fx;
				fx=p[{fx,fy}].first;
				fy=p[{tx,fy}].second;
			}
			q.push({fx,fy});
			step[fx][fy]=min(step[x][y]+1,step[fx][fy]);
		}
	}
	if(step[x2][y2]!=0x3f3f3f3f)
	cout<<step[x2][y2];
	else
	cout<<-1;
	return 0;
}



5.E

这题脑筋急转弯,cf原,题面说的很玄乎,容易把人带进沟里,但其实就是最后一把谁赢了,谁就是最终的获胜者,是本场最简单的题

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	string s;
	cin>>s;
	cout<<s.back();
	return 0;
}



6.F

这题找规律吧,其实有点dp的思想,因为大方向只能往右走,所以每个点的方案数只能由它的左边和左上边推出,想到这个就很简单,就是个斐波那契数列.建议用dp求,不要用dfs求,dfs要写记忆化才能不超时!

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5;
const int mod=1e9+7;
int dp[maxn];
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n;
	cin>>n;
	dp[1]=1,dp[2]=1;
	for(int i=3;i<=n;i++)
	{
		dp[i]=(dp[i-1]+dp[i-2])%mod;
	}
	cout<<dp[n];
	return 0;
}



7.I

这题纯签到,就遍历一个二维数组,维护一个最大值和一个行标

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n,m;
	cin>>n>>m;
	int a[n+5][m+5];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
		}
	}
	int ma=-1,idx;
	for(int i=1;i<=n;i++)
	{
		int cnt=0;
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]==1)
			cnt++;
		}
		if(cnt>ma)
		{
			ma=cnt;
			idx=i;
		}
	} 
	cout<<idx<<" "<<ma; 
	return 0;
}

8.J

这题要贪心,因为普通去掉一位数只能降一位,而如果第二位是0,去掉第一位数就可以降大于等于两位,这是最优的,需要特判,如果第二位不是0就只能降一位了,删掉第一个出现的最大的那位数就行,最后还有一个去除前导0的操作.

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n;
	cin>>n;
	string s;
	cin>>s;
	int ma=-1,idx=s.size()-1;
	string st;
	if(s[1]=='0'&&n>1)
	{
		s.erase(s.begin());
	}
	else
	{
		st.push_back(0);
	for(int i=0;i<s.size();i++)
	{
		if(s[i]>=s[st.back()])
		{
			st.push_back(i);
		}
		else
		{
			idx=st.back();
			break;
		}
	}
	
	s.erase(s.begin()+idx);
	}
	if(s.size()==0)
	{
		cout<<0;
	}
	else
	{
		int start=s.size();
		for(int i=0;i<s.size();i++)
		{
			if(s[i]!='0')
			{
				start=i;
				break;
			}
		}
		if(start==s.size())
		{
			cout<<0;
		}
		else
		{
			cout<<s.substr(start);
		}
	}
	return 0;
}



9.K

这题容易以为是dp,但又不知道咋弄,其实是个数学题,结论就是进行k次操作一直正着走能走到多少层,如果n刚好比其中某个数少一,就是操作数加1,如果不是,答案就是那个第一个比它大的数的操作数比如走四步可以走到7,那6的答案就是5,5的答案就是4,因为5比七小二,那只要第1次操作走负1就少了2,正好凑成5

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n;
bool check(int x)
{
    if(x*(x+1)/2>=n)
    {
        return true;
    }
    else
    return false;
}
int bfind()
{
    int l=0,r=1e6;
    while(l+1<r)
    {
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid;
    }
    return r;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n;
        int ans=bfind();
        if(ans*(ans+1)/2==n+1)
        cout<<(ans+1)<<"\n";
        else
        cout<<ans<<"\n";
    }
    return 0;
}

10.L

这题签到,就求个前缀和二分就能搞定

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int n,q;
	cin>>n>>q;
	vector<int>v(n+5),pre(n+5,0);
	for(int i=1;i<=n;i++)
	{
		cin>>v[i];
		pre[i]=pre[i-1]+v[i];
	}	
	while(q--)
	{
		int t;
		cin>>t;
		auto it=lower_bound(pre.begin()+1,pre.begin()+1+n,t);
		if(it!=pre.begin()+1+n)
		{
			cout<<(it-pre.begin())<<"\n";
		}
		else
		{
			cout<<-1<<"\n";
		}
	}
	return 0;

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值