訓練賽題解 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;
}