训练赛题解 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

image-20211025153158903

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;
}
posted @ 2021-10-26 21:55  Shijie_Huang  阅读(778)  评论(0)    收藏  举报