1. 程式人生 > 實用技巧 >19級暑假第一場訓練賽

19級暑假第一場訓練賽

題目出自:Codeforces Round #547 (Div. 3)

A. Game 23

https://codeforces.com/problemset/problem/1141/A

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m;
bool flag;
int cnt;
//資料不大,暴力深搜
void dfs(int now, int step) {
	if (now == m) {
		flag = true;
		cnt = step;
		return;
	}
	if (now > m)return;
	dfs(now * 2, step + 1);
	dfs(now * 3, step + 1);
}
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> n >> m;
	dfs(n, 0);
	if (flag)cout << cnt << endl;
	else cout << -1 << endl;
}

B. Maximal Continuous Rest

https://codeforces.com/problemset/problem/1141/B

作兩個週期大小,最大連續序列

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 50;
int n, a[N];
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> n; bool flag = true;
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		if (a[i] != 0)flag = false;
	}
	if (flag)return cout << 0, 0;
	for (int i = n; i < 2 * n; i++) a[i] = a[i - n];
	int cnt = 0, msum = 0;
	for (int i = 0; i < 2 * n; i++){
		if (a[i] == 1 && a[i + 1] == 1)
			cnt++;
		if (cnt > msum)
			msum = cnt;
		if (a[i] == 0)
			cnt = 1;
	}
	cout << msum << endl;	
}

C. Polycarp Restores Permutation

https://codeforces.com/problemset/problem/1141/C

做的時候用推匯出數學公式但沒做特判,導致WA

WA程式碼:

#include<bits/stdc++.h>
using namespace std;
const int N = 4e5 + 50;
int n, a[N];
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> n; bool flag = true;
	for (int i = 0; i < n; ++i) {
		cin >> a[i];
		if (a[i] != 0)flag = false;
	}
	if (flag)return cout << 0, 0;
	for (int i = n; i < 2 * n; i++) a[i] = a[i - n];
	int cnt = 0, msum = 0;
	for (int i = 0; i < 2 * n; i++){
		if (a[i] == 1 && a[i + 1] == 1)
			cnt++;
		if (cnt > msum)
			msum = cnt;
		if (a[i] == 0)
			cnt = 1;
	}
	cout << msum << endl;	
}

另一種思路

另p陣列首個為0.求出p陣列,再得到p陣列中最小的值,將p中所有數減掉最小值再加1得到原p。

同時記錄原p中每個數出現的次數。超過一次,說明不能還原 。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 2e5 + 10;
LL a[MAXN];
map<LL, int> b;

int main(){
    int n, v;
    cin >> n;
    a[0] = 0;
    LL sum = 0, mmin = 0;
    for (int i = 2;i <= n;i++){
        cin >> v;
        a[i] = a[i - 1] + v;
        sum += a[i];
        mmin = min(mmin, a[i]);
    }
    for (int i = 1;i <= n;i++){
        a[i] = a[i] - mmin + 1;
        if (b[a[i]] == 1 || a[i] > n) {
            cout << -1 << endl;
            return 0;
        }
        b[a[i]] = 1;
    }
    for (int i = 1;i <= n;i++)
        cout << a[i] << ' ' ;
    cout << endl;
    return 0;
}

使用set容器

#include <bits/stdc++.h>
using namespace std;
int64_t n, m, mx, i, x, p[222000];
set<int64_t> s;
int main(){
    cin >> n;
    s.insert(0);
    for (i = 1; i < n; i++){
        cin >> x;
        p[i] = p[i - 1] + x;
        m = min(m, p[i]);
        mx = max(mx, p[i]);
        s.insert(p[i]);
    }
    if (mx - m != n - 1 || s.size() < n)cout << -1;
    else for (i = 0; i < n; i++)cout << p[i] + 1 - m << " ";
}

D. Colored Boots

沒有做出來,感覺可以二分圖做。

https://codeforces.com/problemset/problem/1141/D

貼上dalao題解

思路:

找到所有小寫字母,將它們所有的下標位置存入一個數組,然後每次查詢相同的字母在s1,s2中的相同字母的位置,

然後輸出就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<utility>
using namespace std;
const int maxn = 2e5+10;
char s1[maxn],s2[maxn];
vector <int> v1[30],v2[30];
vector <pair <int,int> > ans;
int main(void)
{
	int n,i,j,cnt = 0;
	scanf("%d",&n);
	scanf("%s%s",s1+1,s2+1);
	for(i=1;i<=n;i++){
		if(s1[i]>='a'&&s1[i]<='z') v1[s1[i]-'a'].push_back(i);
		else v1[26].push_back(i);
		if(s2[i]>='a'&&s2[i]<='z') v2[s2[i]-'a'].push_back(i);
		else v2[26].push_back(i);
	}
	for(i=0;i<=26;i++){
		while(v1[i].size()>0&&v2[i].size()>0){
			ans.push_back(make_pair(v1[i][v1[i].size()-1],v2[i][v2[i].size()-1]));
			v1[i].pop_back();
			v2[i].pop_back();cnt++;
		}
		while(v1[i].size()>0&&v2[26].size()>0){
			ans.push_back(make_pair(v1[i][v1[i].size()-1],v2[26][v2[26].size()-1]));
			v1[i].pop_back();
			v2[26].pop_back();cnt++;
		}
		while(v1[26].size()>0&&v2[i].size()>0){
			ans.push_back(make_pair(v1[26][v1[26].size()-1],v2[i][v2[i].size()-1]));
			v1[26].pop_back();
			v2[i].pop_back();cnt++;
		}
	}
	printf("%d\n",cnt);
	for(i=0;i<cnt;i++){
		printf("%d %d\n",ans[i].first,ans[i].second);
	}
	return 0;
}

E. Superhero Battle

https://codeforces.com/problemset/problem/1141/E

題意:

有一個怪獸,初始血量為HHH,他的血量變化情況是一個長度為nnn輪的週期。問怪獸會在第幾輪死去。
做法

首先如果怪獸血量在一個週期內不曾小於等於000而且每個週期之後怪獸血量增加,直接輸出−1。

之後要知道,怪獸在某個完整的週期之前到達x血量,怪獸就撐不過這輪。
這個 \(x\) 的求法就是遍歷一遍週期,找到某個時刻怪獸血量消耗最多。

之後就假設怪獸初始血量為 \(H−x\) 看怪獸能撐過幾個完整的輪,設這裡輪數為 \(k\) ,每輪怪獸血量減少 \(sum\) ,則要滿足

\[sum * k + x >= H \]

\[k >= (H - x) / sum \]

所以不等式右面要上取整得到 \(k\) ,之後再 \(O(n)\) 的進行一個週期看怪獸在第幾輪死即可。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
ll a[maxn];
int main() {
    int flag = 0, mark;
    ll h, n, sum = 0, mi = inf;
    cin >> h >> n;
    ll g = h;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        sum += a[i];
        mi = min(mi, sum);
        g += a[i];
        if (g <= 0 && !flag) mark = i, flag = 1;
    }
    if (flag) return cout << mark << endl, 0;
    if (sum >= 0) return cout << -1 << endl, 0;
    sum = -sum;
    h += mi;
    ll ans = h / sum * n;
    ll cur = h % sum - mi;
    while (cur > 0) {
        for (int i = 1; i <= n; i++) {
            cur += a[i];
            ans++;
            if (cur <= 0) break;
        }
    }
    printf("%lld\n", ans);
    return 0;
}