2021年合肥學院校賽題解
A.我愛合院
思路
直接輸出"HFUU"
即可。
代碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout << "HFUU";
return 0;
}
B.簡單的工資發放問題
思路
第一天的工資為1
,后面兩天的工資為2, 2
,后面三天的工資為3,3,3
......
數據范圍為1 - 10000
,方法很多, 我們可以先預處理出每天的工資,然后循環一次累加每天的工資即可。時間復雜度O(n)
。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10010;
LL a[N];
int n;
int main()
{
int n;
scanf("%d", &n);
int qwq = 0;
int flag = 1;
for(int i = 1; i <= n; i ++ )
{
a[i] = flag;
++ qwq;
if(qwq == flag)
{
flag ++;
qwq = 0;
}
}
LL ans = 0;
for(int i = 1; i <= n; i ++ ) ans += a[i];
printf("%lld",ans);
return 0;
}
C.簡單的計算幾何問題
思路
本題我們可以對所有的點求一個凸包,答案就是凸包的周長。
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define x first
#define y second
using namespace std;
const int N = 10010;
typedef pair<double,double> PDD;
int n;
PDD q[N];
int stk[N];
bool st[N];
PDD operator-(PDD a, PDD b)
{
return {a.x - b.x, a.y - b.y};
}
double cross(PDD a, PDD b)
{
return a.x * b.y - b.x * a.y;
}
double area(PDD a, PDD b, PDD c)
{
return cross(b - a, c - a);
}
double get_dist(PDD a, PDD b)
{
double xx = a.x - b.x;
double yy = a.y - b.y;
return sqrt(xx * xx + yy * yy);
}
double Andrew()
{
sort(q + 1, q + 1 + n);
int top = 0;
for(int i = 1; i <= n; i ++ )
{
while(top >= 2 && area(q[stk[top - 1]], q[stk[top]], q[i]) <= 0)
{
if(area(q[stk[top - 1]], q[stk[top]], q[i]) < 0)
st[stk[top -- ]] = false;
else top --;
}
stk[ ++ top] = i;
st[i] = true;
}
st[1] = false;
for(int i = n; i >= 1; i -- )
{
if(st[i]) continue;
while(top >= 2 && area(q[stk[top - 1]], q[stk[top]], q[i]) <= 0)
{
if(area(q[stk[top - 1]], q[stk[top]], q[i]) < 0)
st[stk[top -- ]] = false;
else top --;
}
stk[++ top] = i;
st[i] = true;
}
double res = 0;
for(int i = 2; i <= top; i ++ )
res += get_dist(q[stk[i]], q[stk[i - 1]]);
return res;
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i ++ ) scanf("%lf %lf",&q[i].x, &q[i].y);
double res = Andrew();
printf("%.2lf", res);
return 0;
}
D.簡單的理財問題
思路:
本題是純模擬題。
整個過程是確定的,從前往后依次模擬整個流程即可。
模擬過程中記錄如下幾個值:
total
: 存在姐姐那里的總錢數;
remain
: bs
當前剩在自己手里的錢數;
cur
:讀入的值,表示當前這個月的生活開銷
依次枚舉每個月,對於當前這個月,首先判斷總共能拿到的錢數是否夠用,即判斷:
cur + 300 >= cur
是否成立;
如果夠用,則將整百部分交給姐姐,自己剩下最多兩位數的錢。
最后的總錢數是:total * 12 + remain
。
代碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int total = 0, remain = 0;
for (int i = 1; i <= 12; i ++ )
{
int cur;
cin >> cur;
if (remain + 300 < cur)
{
total = -i;
break;
}
remain += 300 - cur;
total += remain / 100 * 120;
remain %= 100;
}
if (total >= 0) total += remain;
cout << total << endl;
return 0;
}
E.簡單的路徑規划問題
思路
裸的最短路問題,方法很多,套朴素Dijkstra
都能過,堆優化的當然更好。
朴素Dijkstra
的時間復雜度 \(O(n^2)\)。
優化的Dijkstra
的時間復雜度為\(O(nlogn)\)。
代碼
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 510;
int n, m;
int g[N][N];
int dist[N];
bool st[N];
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n - 1; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
for (int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
st[t] = true;
}
if (dist[n] == 0x3f3f3f3f) return -1;
return dist[n];
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = min(g[a][b], c);
}
printf("%d\n", dijkstra());
return 0;
}
F.簡單的字符串問題
思路:
本題要求長度大於\(1\)且最短的回文串,只有三種情況:
\(1\).字符串里面出現連續兩個相同的字符 , \(exp: .....aa.....\) 答案是$ 2 $
\(2\).字符串中出現長度為3的回文串,例如: $...qwq... $答案是 \(3\)
\(3\).字符串中只有長度為1的回文串例如:\(abcdefg\),答案是 \(-1\)
其余的回文串如果存在則一定長於第一第二種情況,所以答案只有\(2, 3, -1\)。
時間復雜度為\(O(n)\)。\(n\)為字符串的長度。
代碼:
#include <cstring>
#include <iostream>
using namespace std;
string s;
int main()
{
cin >> s;
int len = s.length();
for(int i = 1; i < len; i ++ )
{
if(s[i] == s[i - 1]) {
printf("2\n");
return 0;
}
}
for(int i = 1; i < len; i ++ )
{
if(s[i - 1] == s[i + 1] && i + 1 < len){
printf("3\n");
return 0;
}
}
printf("-1\n");
return 0;
}
G.簡單的排序問題
思路:
本題的思路很明顯,先把所有的時間段排個序,然后選擇時間段較長的即可,排序的話大部分排序方式都能過,冒泡也能過。
時間復雜度是關於你的排序方式,冒泡為\(O(n^2)\)或者快排是\(O(nlogn)\)
代碼:
#include <stdio.h>
#define N 10010
int main()
{
int n;
int a[N];
scanf("%d",&n);
for(int i = 1; i<= n; i ++ ) scanf("%d",&a[i]);
int temp, i, j;
for (i = 1; i <= n; i++) //進行9次比較
for (j = 1; j <= n - i; j++) //在每次中進行10-i-1次比較
if (a[j] > a[j + 1]) //按升序排序,降序用<
{
temp = a[j + 1]; //交換相鄰的兩個元素
a[j + 1] = a[j];
a[j] = temp;
}
int sum = 0;
for (i = n / 2 + 1; i <= n; i++) sum += a[i];
printf("%lld", sum);
}
H.簡單的桌游問題
思路:
題意可以理解成不能出現邊長都為1的三角形路徑,根據這個要求,可以發現,當將一個元素作為起點,遍歷剩余的棋子作為一個個終點,這樣的連接方式是符合題意要求的。同時,為了保證答案的最大化,我們可以將更多的棋子作為起點方,剩余的棋子當作終點方,顯然當起點和終點的棋子差距最小時,答案是最大的,所以本題可以等價成左右兩排數求最多的連接數。
時間復雜度為\(O(1)\).
代碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 998244353;
int main() {
int n;
while (cin >> n)
cout << (n / 2) * (n - n / 2) << endl;
return 0;
}
I.簡單的數據結構問題
思路:
本題的每組數據的答案都在一個不斷更新的長度為一整天的數組中,注意到每次輸入時的ti是遞增的,所以可以類比成一個滑動的窗口不斷單調滑動,所以本題我們需要用到隊列來處理滑動窗口,用隊列中隊頭和隊尾的更新來模擬窗口的滑動,在滑動時不斷更新數組儲存的國籍數據。
時間復雜度\(O(K)\)。
代碼:
#include<iostream>
using namespace std;
int s,i,n,t,k,r,w[100001],x[300002],y[300002];
int main(){
cin>>n;
while(n--){
cin>>t>>k;
while(k--){
y[++r]=t;cin>>x[r];
if(!w[x[r]])s++;
w[x[r]]++;
}
while(t-y[i]>=86400)
if(!--w[x[i++]])s--;
cout<<s<<endl;
}
return 0;
}
J.合院生日快樂
思路:
輸出$ n - 40 + 2020$即可
代碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
cout << n - 40 + 2020 << endl;
return 0;
}