1. 程式人生 > 其它 >訓練賽題解 The 2020 ICPC Asia Shenyang Regional Programming Contest

訓練賽題解 The 2020 ICPC Asia Shenyang Regional Programming Contest

The 2020 ICPC Asia Shenyang Regional Programming Contest

G. The Witchwood

計算前K大個數的和。

//====================================================================================================
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
	ll ans = 1 % mod;
	while (b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
inline ll inv(ll a, ll mod)
{
	return qmi(a, mod - 2, mod);
}
int main()
{
	vector<int> a;
	int n, k;
	cin >> n >> k;
	int x;
	for (int i = 0; i < n; i++)
	{
		cin >> x;
		a.emplace_back(x);
	}
	ll ans = 0;
	sort(a.begin(), a.end(), greater());
	for (int i = 0; i < k; i++)
		ans += a[i];
	cout << ans;
	return 0;
}

F. Kobolds and Catacombs

給一個數組,讓我們切分該陣列,分成k段,對這k段內部排序,然後連線起來陣列是遞增的。

對一段內部,必然有一個最大值一個最小值,只要下一段的最小值大於當前段的最大值,就可以多劃分一個。

所以直接找對於每一個數能接受的最大值或者最小值即可。

其實就是找這個數往前的最大值,這個數往後的最小值。

//====================================================================================================
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
    ll ans = 1 % mod;
    while (b)
    {
        if (b & 1)
            ans = ans * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return ans % mod;
}
inline ll inv(ll a, ll mod)
{
    return qmi(a, mod - 2, mod);
}
const int N = 1000010;
int a[N];
int ans = 0;
int maxn[N], minn[N];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    maxn[0] = 0;
    minn[n + 1] = 0x3f3f3f3f;
    for (int i = 1; i <= n; i++)
        maxn[i] = max(maxn[i - 1], a[i]);
    for (int i = n; i; i--)
        minn[i] = min(minn[i + 1], a[i]);
    for (int i = 1; i <= n; i++)
    {
        if (maxn[i] <= minn[i + 1])
            ans++;
    }
    cout << ans;
    return 0;
}

D. Journey to Un'Goro

讓我們構造一個長度為n的只包含'b'和'r'的字串,要求所構造的字串的子序列滿意的個數最多。

滿意的定義:對於序列\([l,r]\),其中'r'出現的次數是奇數,那麼對於該字串就是滿意的。

按字典序輸出前100個。

首先需要求\([l,r]\)內r出現的個數,那麼想到的就是字首和。

我們定義陣列\(g[N]\),\(g[i]\)表示字串前\(i\)位裡\(r\)出現的個數。

那麼對於序列\([l,r]\)\(r\)出現的個數就是\(g[r]-g[l-1]\)

只有\(g[r]\)\(g[l-1]\)奇偶性不同的時候,該字串才滿意

設這些字首和裡有x個奇數,y個偶數,且x+y=n,此時我們的答案就是xy

則由均值不等式:$ x+y\ge2\sqrt{xy} $ 得到:\(xy\le (\frac{x+y}{2})^2\),當且僅當x=y時取得等號

即:\(x=y=\frac{n}{2}\)時,答案最大。

因為只需要輸出前100個,搜尋即可。

//====================================================================================================
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
	ll ans = 1 % mod;
	while (b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
inline ll inv(ll a, ll mod)
{
	return qmi(a, mod - 2, mod);
}
const int N = 1000010;
char s[N];
long long n;
long long cnt = 0;
int out;
void dfs(int i, int ou, int ji, int las)
{
	if (cnt >= 100 || ou > out || ji > out)
		return;
	if (i == n)
	{
		cnt++;
		cout << s << endl;
		return;
	}
	if (las % 2 == 0)
	{ //這一個是偶數
		s[i] = 'b';
		dfs(i + 1, ou + 1, ji, las);
		s[i] = 'r';
		dfs(i + 1, ou, ji + 1, las + 1);
	}
	else
	{ //這一個是奇數
		s[i] = 'b';
		dfs(i + 1, ou, ji + 1, las);
		s[i] = 'r';
		dfs(i + 1, ou + 1, ji, las + 1);
	}
}
int main()
{
	cin >> n;
	cout << ((n + 2) / 2) * ((n + 1) / 2) << endl;
	out = (n + 2) / 2;
	dfs(0, 1, 0, 0);
	return 0;
}

I. Rise of Shadows

一個時鐘H小時,M分鐘,給一個A,問時鐘分鐘角度小於 \(\alpha=\frac{2πA}{HM}\)的分鐘時刻個數

不難想到用解決追及相遇問題的辦法來解決這個問題

分針的速度為\(\frac{2\pi}{M}\),時針的速度為\(\frac{2\pi A}{HM}\),假設時針不動,那麼分針的速度為\((\frac{2\pi}{M}-\frac{2\pi A}{HM})=\frac{2\pi A}{HM}(H-1)\)

我們可以根據題意列出不等式:\(-\alpha\le [t*\frac{2\pi A}{HM}(H-1)] \mod (HM) \le \alpha\)

化簡得:$-A \le t*(H-1) \mod (HM) \le A $ \(t\in[0,hm]\)

由於: \(a*b\equiv b*c \mod d\) 等價於 \(a\equiv c \mod \frac{d}{gcd(b,d)}\)

故將原式化為:\(\frac{-A}{gcd(H-1,HM)} \le t*\frac{(H-1)}{gcd(H-1,HM)} \mod \frac{(HM)}{gcd(H-1,HM)} \le \frac{A}{gcd(H-1,HM)}\) \(t\in[0,\frac{HM}{gcd(H-1,HM)}]\)

此時,t在正半軸有\(\frac{A}{gcd(H-1,HM)}\)個解,在負半軸也有\(\frac{A}{gcd(H-1,HM)}\)個解,加上零點就是\(2*\frac{A}{gcd(H-1,HM)}\)個解,加上原點就是\(2*\frac{A}{gcd(H-1,HM)}+1\)個解,其中時間的取值範圍是\([0,\frac{HM}{gcd(H-1,HM)}]\),那麼我們只需要在單個區間的基礎上再乘上\(gcd(H-1,HM)\)就是答案,答案最大值是HM,需要與其取min。

//====================================================================================================
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
	ll ans = 1 % mod;
	while (b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
inline ll inv(ll a, ll mod)
{
	return qmi(a, mod - 2, mod);
}
int main()
{
	ll H, M, A;
	cin >> H >> M >> A;
	ll pr = __gcd(H - 1, H * M);
	cout << min(H * M, pr * (2 * (A / pr) + 1));
	return 0;
}

H. The Boomsday Project

dp,對每次租車進行操作,在所有優惠裡轉移,同時維護每種卡最早的可用優惠的時間。

//====================================================================================================
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <sstream>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<double, double> PUU;
#define RUSH cin.tie(), cout.tie(), ios::sync_with_stdio(false)
#define pb push_back
#define eb emplace_back
#define pai acos(-1.0)
inline ll qmi(ll a, ll b, ll mod)
{
	ll ans = 1 % mod;
	while (b)
	{
		if (b & 1)
			ans = ans * a % mod;
		b >>= 1;
		a = a * a % mod;
	}
	return ans % mod;
}
inline ll inv(ll a, ll mod)
{
	return qmi(a, mod - 2, mod);
}
const int N = 300010;
int f[N];
int d[510], k[510], c[510], a[N];
int pre[510];
int cnt = 0;
int n, m, r;
int main()
{
	cin >> n >> m >> r;
	for (int i = 1; i <= n; i++)
		cin >> d[i] >> k[i] >> c[i]; //期限d,次數k,花費c
	for (int i = 1; i <= m; i++)
	{
		int p, q;
		cin >> p >> q;
		while (q--)
			a[++cnt] = p; //第cnt輛車是第p天買的
	}
	sort(a + 1, a + 1 + cnt); //按購買天數排序
	for (int i = 1; i <= cnt; i++)
	{
		f[i] = f[i - 1] + r;
		for (int j = 1; j <= n; j++)
		{ //列舉優惠卡
			while (a[i] - a[pre[j] + 1] >= d[j] || i - pre[j] > k[j])
				pre[j]++;						//如果優惠卡期限超過,或者優惠次數不足,那麼使用該優惠卡的最先天數往後移動一天
			f[i] = min(f[i], f[pre[j]] + c[j]); //取了該優惠卡後的最小值計算
		}
	}
	cout << f[cnt];
	return 0;
}

K.Scholomance Academy

一個模擬算AUC寫了一年沒寫出來,老是有一個點不過

怒了

下方是Scholomance Academy_he_qingjun的部落格-CSDN部落格的程式碼

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;

struct node{
	char op;
	int  s;
}a[100050];

int cmp(node a,node b){
	if(a.s == b.s){
		return a.op < b.op;
	}else
		return a.s < b.s;
}

int main(){
int n;
scanf("%d",&n);
getchar();
double s1 = 0,s2 = 0;

for(int i = 1;i<=n;i++){
	scanf("%c%d",&a[i].op,&a[i].s);
	getchar();
	if(a[i].op == '+') s1++;
	else s2++;
}

sort(a+1,a+n+1,cmp);

double ans = 0.0,t = 1.0;

for(int i = 1;i<=n;i++){
	
	if(a[i].op == '-') ans += t * 1.0 / s2;
	else t = t - 1.0 / s1; 
}
printf("%.10lf",ans);
return 0;
}