考研选手为了ec-final开始复健(
A题 I Scream
注意需要将milk solids-not-fat和milk fat加起来就好了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int > PII;
const int N = 1e5 + 10;
int main(){
#ifndef ONLINE_JUDGE
freopen("my_in.txt", "r", stdin);
freopen("my_out.txt", "w", stdout);
#endif
int a, b;
scanf("%d %d", &a, &b);
if(a + b >= 15 && b >= 8) cout<<1<<endl;
else if(a + b >= 10 && b >= 3) cout<<2<<endl;
else if(a + b >= 3) cout<<3<<endl;
else cout<<4<<endl;
return 0;
}
B题 Job Assignment
由于N的范围很小只有一千,可以直接枚举一下
做的时候没有管范围直接把A和B排了个序,判断一下A和B中的最小值是否来自同一个i,不是的话直接输出二者最大值,是的话就判断一下(max(A_1, B_2)和max(A_2, B_1)和A_1+B_1)三者哪个最小就好了
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int > PII;
const int N = 1010;
PII a[N], b[N];
bool cmp(PII x, PII y){
return x.first < y.first;
}
int main(){
int n;
cin>>n;
for(int i = 0; i < n; i ++){
scanf("%d %d", &a[i].first, &b[i].first);
a[i].second = i, b[i].second = i;
}
sort(a, a + n, cmp);
sort(b, b + n, cmp);
if(a[0].second == b[0].second){
int x = a[0].first + b[0].first;
for(int i = 1; i < n; i ++){
int y = max(b[i].first, a[0].first);
if(y < x){
x = y; break;
}
else{
break;
}
}
for(int i = 1; i < n; i ++){
int y = max(a[i].first, b[0].first);
if(y < x){
x = y; break;
}
else
break;
}
cout<<x<<endl;
}
else {
cout<<max(a[0].first,b[0].first)<<endl;
}
return 0;
}
好像写了很傻的代码
C题 Squared Error
两种方法
1.由于(|A_i| leq 200),可以将这3e5个数全部归到200以内,只用算这200个数的差平方再乘上每个数出现的次数。
2.对题目中的公式进行推导,如下图
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 3e5 + 10;
vector<int> a(maxn);
int main(){
int n;
long long ans = 0, sum = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++){
scanf("%d", &a[i]);
sum += a[i];
ans += a[i] * a[i];
}
ans *= n;
ans -= sum * sum;
cout<<ans<<endl;
return 0;
}
D题 Journey
是一道dp题
假设当前有i个点已经连通,d[i]代表在此基础上要使图全部连通(即n个点都连通)时所需步数的期望。
通过定义可知起始点为d[n] = 0,需从后往前推
(d[i] = frac{n - i}{n}d[i+1] + frac{i}{n}d[i] + 1)
也就是有两种状态可以转移至d[i],一种是从d[i+1]中减掉一个已经连通的点——选一个d[i]中未连通的点,所以是(n-i)/n * d[i+1],另一种是从d[i]选一个已连通的点,也就是i/n * d[i],最后再加上这一步的步数1。
化简得到(d[i] = d[i+1] + frac{n}{n - i})
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
double a[N];
int main(){
int n;
cin >> n;
a[n] = 0.0;
for(int i = n - 1; i > 0; i --){
a[i] = a[i + 1] + (double)n / (double)(n - i);
}
printf("%.6lf
", a[1]);
return 0;
}
E题 Mex Min
求滑动区间最小mex值
用类似滑动窗口做,将第一个区间算完后,将mex值看成从左往右从小到大的一行中第一个空着的地方。考虑几种情况:
1.移出区间的值使mex左边空了一格,mex左移
2.移出和新进区间的值正好相同,mex不变
3.新进区间的值把mex的空填上了,需要继续往右找空的地方
4.在mex的右边进行操作
由于只需要求mex最小值,所以只考虑1的情况就可以了
判断移出区间的值计数是否变为0,变为0则取当前mex和该值的最小值
注意算第一个区间的时候,for循环要循环至max(Ai)+1
#include <bits/stdc++.h>
using namespace std;
const int N = 1500010;
int a[N], ct[N];
int main(){
int n, m, res = 1e9;
scanf("%d %d", &n, &m);
if(n == 1){
cout<<1<<endl;
return 0;
}
for(int i = 0; i < n; i ++){
scanf("%d", &a[i]);
if(i < m)
ct[a[i]] ++;
}
for(int i = 0; i <= n; i ++){
if(ct[i] == 0){
res = i;
break;
}
}
for(int i = m; i < n ; i ++){
int cnt = -1;
ct[a[i - m]] --;
ct[a[i]] ++;
if(ct[a[i - m]] == 0)
res = min(res, a[i - m]);
if(res == 0){
cout<<res<<endl;
return 0;
}
}
cout<<res<<endl;
return 0;
}
F题明天补上~