小测验题解

前言

蒟蒻第一次出题,数据几次出锅,幸好队友补救,才基本没什么大问题。这回题目主要分三档,ABCD语法题,面向基础;E简单算法题,就是上一周程协讲的内容,听了上周严鸽鸽课的同学应该都没太大问题;F思维题,本来想自己出一道的,但是奈何自己太菜,想不到很巧妙的思维题,刚好想起来不久前cf做过的一道c题,就直接翻译过来用了;G是一道防ak题,对新生来说应该太难了,灵感来源于上学期数据结构和离散数学老师在和我争论dijkstra的时间复杂度到底是 O ( n 2 ) O (n^2) O(n2)还是 O ( n l o g 2 n ) O(nlog_2 n) Onlog2n),于是就专门拉了一道比较模板但是卡了 O ( n 2 ) O(n^2) O(n2)的小白月赛原题。

正文

A(语法)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() { cout << "你好,小恐龙!\n"; }

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

B(语法)

tag本来是想出一道数组求和的,但是奈何单独太难考察就放弃了。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  cin >> n;
  int sum = 0;
  for (int i = 1; i <= n; i++) cin >> a[i];
  for (int i = 1; i <= n; i++) sum += a[i];
  cout << sum << endl;
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

C(语法)

队友想的一道题(题面我写的,别问,问就是舟批! ),本来是想让距离还要开方的,但是后来学长提醒因为有精度问题要写spj就放弃了,直接不需要开方了,tag也是数组?(大概)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
struct loc {
  int a, b, c, d;
} s[N], now;

int cal(loc p, loc q) {
  return (p.a - q.a) * (p.a - q.a) + (p.b - q.b) * (p.b - q.b) +
         (p.c - q.c) * (p.c - q.c) + (p.d - q.d) * (p.d - q.d);
}//计算距离

void solve() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> s[i].a >> s[i].b >> s[i].c >> s[i].d;
  }//读入坐标
  cin >> now.a >> now.b >> now.c >> now.d;
  int res = 0;
  for (int i = 1; i <= n; i++) {
    res = min(res, cal(s[i], now));//比较大小
  }
  cout<<res<<endl;
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

D(语法)

由于出题前一天才被炉石战棋拯救,没有打铁,于是决定最后一题出一道炉石题,本质其实是数组遍历

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n;
int a[N];

void solve() {
  int x;
  cin>>n>>x;
  for(int i=1;i<=n;i++) cin>>a[i];
  int q;
  cin>>q;
  while(q--) {
  	int l,r;
  	cin>>l>>r;
  	int res=0;
  	for(int i=l;i<=r;i++) {
  		if(a[i]<=x) res++;
  	}
  	cout<<res<<endl;
  }
}

signed main() {
  IOS;
  int t = 1;
  // cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

E(前缀和)

进阶题想出一道比较简单的算法题,然后就想到了第一次培训讲的前缀和,出了个板题。j结果这道板题还锅了两次,第一次是爆了int,幸好队友验题的时候发现了,紧急调小数据;第二次是数据造的太弱了 O ( n 2 ) O(n^2) O(n2)的暴力都能卡过去,然后手造了几组大数据。据队友说双指针也能做,想想好像雀食, O ( n ) O(n) O(n)扫一遍的确能写。(反正这题时间复杂度就是 O ( n ) O(n) O(n)否则会被卡掉)

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n,k;
int a[N];
int sum[N];
void solve() {
  cin>>n>>k;
  for(int i=1;i<=n;i++) cin>>a[i];
  for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];//求前i个题分数和
  int res=0;
  for(int i=1;i<=n-k+1;i++) {
  	res=max(res,sum[i+k-1]-sum[i-1]);//求连续k个题的分值最大和
  }
  cout<<res<<endl;
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

F(思维)

cf原题,我只是个翻译,原题链接,第一次做的时候想复杂了,以为是个nim游戏,然后突然发现是个单纯的思维博弈。
我们可以发现,如果只有一个非零数的时候,其实胜负已经定了,以为只有A移动有值的数会减,然后把0移到前面去B就输了,那么我们更进一步,如果只有两个数,且两个数都是非零数呢?我们会发现,其实A永远减的是第一个数,B减的永远都是第二个数,所以只要比较前面两个数哪个更小就行了,如果第一个数小于等于第二个数,必然是A输,否则B输。那么我们再推广一下,如果n更大,其实A/B每次移动到前面的数永远是从数组第二个开始最小的那个,因为这样B/A能移动的次数才是最少,于是,其实我们就推出来结论,看刚开始的状态第一个元素是否是唯一的最小的元素(要求唯一是因为如果不唯一在A第一次移动之后其实第一个元素已经减一了,就会变成唯一的最小值),如果是,则B只要每次把这个数移到第一位,那么A必输,否则B必输。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n, k;
int a[N];

void solve() {
  cin >> n;
  for (int i = 1; i <= n; i++) cin >> a[i];
  if (a[1] == *min_element(a + 1, a + n + 1))
    cout << "B\n";
  else
    cout << "A\n";
}

signed main() {
  IOS;
  int t = 1;
  cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}

G(最短路dijkstra)

某场牛客小白月赛原题,原题链接
其实就是在基础的建图上加了转换季节的耗费与不转换耗费的时间的比较,跑一遍dijkstra就可以做了(当然dijkstra需要堆优化 O ( n 2 ) O(n^2) O(n2)的时间复杂度是显然过不了的,堆优化后时间复杂度是 O ( n l o g 2 n ) O(nlog_2 n) O(nlog2n)),具体的dijkstra可以看我的这篇博客,离散实验报告刚好也写了详细注释。博客链接

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
int n,m;
int type[N];
vector<PII>g[N];//存图
int st[N];
int dist[N];

void dijkstra(int start) {
	memset(dist,0x3f,sizeof dist);
	dist[start]=0;
	priority_queue<PII,vector<PII>,greater<PII>>q;
	q.push({0,start});
	while(q.size()) {
		auto d=q.top().first,u=q.top().second;
		q.pop();
		if(st[u]) continue;
		st[u]=1;
		for(auto [v,w]:g[u]) {
			if(dist[v]>w+d) {
				dist[v]=w+d;
				q.push({dist[v],v});
			}
		}
	}
	return;
}

void solve() {
  cin>>n>>m;
  int x,y,z;
  cin>>x>>y>>z;
  for(int i=1;i<=n;i++) cin>>type[i];//记录城市类型
  for(int i=1;i<=m;i++) {
  	int u,v;
  	cin>>u>>v;
  	if(type[u]==type[v]) {
  		g[u].push_back({v,min(x,y+z)});
  		g[v].push_back({u,min(x,y+z)});
  	} 
  	else {
  		g[u].push_back({v,min(y,x+z)});
  		g[v].push_back({u,min(y,x+z)});//比较耗时,将较小的作为边权
  	}
  }
  dijkstra(1);
  cout<<dist[n];
}

signed main() {
  IOS;
  int t = 1;
  //cin >> t;
  for (int i = 1; i <= t; i++) {
    solve();
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值