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

浙公网安备 33010602011771号