Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K |
---|---|---|---|---|---|---|---|---|---|---|---|
8 / 11 | Ø | O | - | - | Ø | - | Ø | O | O | Ø | O |
- O 在比賽中通過
- Ø 賽后通過
- ! 嘗試了但是失敗了
- - 沒有嘗試
Solutions
A. Access Points
題意:
二維平面中給定\(n\)個點\((x_i,y_i)\)。
現在要在二維平面中構造\(n\)個點,其中第\(i\)個點與\((x_i,y_i)\)相連,構造的點可以重合,貢獻為邊權的平方。假設構造的第\(i\)個點為\((X_i,Y_i)\),那么對於\(i<j,X_i\leq X_j,Y_i\leq Y_j\)。
問最后最小的貢獻為多少。
思路:
- 一條邊的貢獻為\((x_i-X_i)^2+(y_i-Y_i)^2\),顯然\(x,y\)獨立,所以我們可以轉化為兩個一維問題。
- 問題轉化為:數軸上給定\(n\)個點,現在要從小到大依次確定一個點,使得對應的貢獻最小。
- 考慮\(\sum(x_i-a)^2\)取最小值時,\(a=average(x_i)\),現在問題是\(\sum(x_i-a_i)^2\)最小,直接將\(x\)分為盡可能多的連續的若干段,每一段取平均值即可。
- 實現的過程可以用一個棧來模擬。
其實就是經典的一個idea的變形,但可以把序列變為連續的若干段,這樣問題就變為經典題目了。
詳見代碼:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/10 14:55:43
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#include <stack>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
int n; cin >> n;
vector <int> x(n), y(n);
for (int i = 0; i < n; i++) {
cin >> x[i] >> y[i];
}
auto gao = [&] (vector <int>& a) {
stack <pair <ll, int>> s;
for (int i = 0; i < n; i++) {
pair <ll, int> now = MP(a[i], 1);
while (!s.empty() && s.top().fi * now.se > now.fi * s.top().se) {
pair <ll, int> t = s.top(); s.pop();
now.fi += t.fi;
now.se += t.se;
}
s.push(now);
}
double res = 0.0;
int id = n - 1;
while (!s.empty()) {
pair <ll, int> t = s.top(); s.pop();
double ave = 1.0 * t.fi / t.se;
for (int i = id; i > id - t.se; i--) {
res += (a[i] - ave) * (a[i] - ave);
}
id -= t.se;
}
return res;
};
double ans = 0.0;
ans += gao(x);
ans += gao(y);
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
B. Brexit Negotiations
拓撲序+貪心。
從前往后貪心正確性得不到保障,但是從后往前即可解決這一問題。
很有意思,拓撲序有時候反着來就能解決很多問題QAQ。
代碼寫着較為復雜。。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 4e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
const int N = 2e5,M = (1<<20);
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
ll ans=1;
for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
return ans;
}
mt19937 mrand(random_device{}());
int a[MAXN],f[MAXN],in[MAXN];
struct cmp{
bool operator ()(int u,int v){
return f[u] < f[v];
}
};
vi G[MAXN];
bool vis[MAXN];
void dfs(int u){
vis[u] = 1;
f[u] = a[u];
for(int v:G[u]){
if(!vis[v])dfs(v);
f[u] = max(f[u], f[v]+1);
}
}
void run(){
int n; cin>>n;
rep(i,1,n){
cin>>a[i];
int x; cin>>x;
rep(j,1,x){
int u; cin>>u;
G[u].push_back(i);
in[i]++;
}
}
rep(i,1,n){
if(!vis[i]){
dfs(i);
}
}
priority_queue<int,vector<int>, cmp> q;
rep(i,1,n)if(!in[i])q.push(i);
int ans=0,cnt=0;
while(!q.empty()){
int u = q.top();q.pop();
ans = max(ans, cnt + a[u]);
for(int v:G[u]){
if((--in[v])==0){
q.push(v);
}
}
cnt++;
}
cout<<ans<<'\n';
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
//freopen("A.in","r",stdin);
//freopen("A.out","w",stdout);
int _=1;
while(_--)run();
return 0;
}
E. Equality Control
題意:
給定兩個表達式,每個表達式有"combine","sorted","shuffle","[]"這四種運算符。其中"[]"中間有一個序列,形如\(x_1,x_2,\cdots,x_i\)。
現在問這兩個表達式是否等價。表達式等價的定義為出現每一種序列的概率都相同。
思路:
首先有幾個觀察:
- 形如shuffle[1,1,1,1]這種相當於沒有進行操作;
- 無視combine操作;
- 表達式樹中,如果某個結點出現了sorted或者shuffle,那么其葉子結點都沒用了,最后只取決於它。
根據這三點很容易看兩個表達式最后是否相等了,但是題目要求出現的概率相等。
那么再加一個條件,在滿足數列相等后,所有shuffle的區間都相等就行(此時概率肯定相等)。如果存在一個區間不相等,那么最后兩個式子肯定不等價。
詳見代碼:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/9 23:22:06
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
typedef pair <vector <int>, vector<pii>> result;
result get(string& s) {
int n = s.length();
vector <int> a, sum(n, -1);
for (int i = 0, j; i < n; i = j + 1) {
j = i;
if (s[i] >= '0' && s[i] <= '9') {
int x = 0;
while (j < n && s[j] >= '0' && s[j] <= '9') {
x = x * 10 + (s[j] - '0');
++j;
}
sum[j - 1] = sz(a);
a.push_back(x);
}
}
vector <pii> seg;
for (int i = 0, j; i < n; i = j + 1) {
j = i;
if (s[i] != 's') continue;
int cnt = 0;
while (j < n && (s[j] < '0' || s[j] > '9')) {
if (s[j] == '(') ++cnt;
++j;
}
int L = INF, R = -1;
while (j < n && cnt > 0) {
if (s[j] == '(') ++cnt;
if (s[j] == ')') --cnt;
if (sum[j] != -1) {
L = min(L, sum[j]);
R = max(R, sum[j]);
}
++j;
}
if (L > R) continue;
sort(a.begin() + L, a.begin() + R + 1);
if (s[i + 1] == 'h' && a[L] != a[R]) {
seg.push_back(MP(L, R));
}
}
return MP(a, seg);
}
void run() {
string s, t; cin >> s >> t;
result A = get(s), B = get(t);
if (A == B) {
cout << "equal" << '\n';
} else {
cout << "not equal" << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
G. Game Design
題意:
給定一些操作符"LRUD",表示往某一個方向走直到遇到障礙。
現在給定終點\((0,0)\),要求構造一個起點以及若干障礙物,使得最后小球能夠到達終點。注意必須是最后一步到達終點,中間到達終點即不合法。
大概圖就是這個樣子:
思路:
一般這種題都會考慮從后往前構造,但這個題中從后往前構造可能會很麻煩。
注意到我們終點的具體位置不重要,假設我們最后到達了某個點\((x,y)\),直接將坐標軸相對於\((x,y)\)平移即可。
所以問題就轉化為了從\((0,0)\)出發,構造一種方案,使得存在一種合法的路徑。
到了這一步就比較簡單了。網格圖中的移動一般是規定一個范圍,每一次范圍會變大或減小。因為這個題從\((0,0)\)開始走,所以我們不斷將范圍變大並且每次走到邊界即可,只要保證小球不會在路徑上碰到障礙物就行。
注意特殊情況:LRL,RLR,UDU,DUD出現在了末尾則肯定不合法,若中間為LRLRLR這種則不擴大范圍。
細節見代碼:
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/9 15:25:32
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 20 + 5;
int n;
string s;
int d;
map <int, map<int, int>> mp;
void sayNo() {
cout << "impossible" << '\n';
exit(0);
}
void run() {
cin >> s;
n = s.length();
if (n >= 3 && s[n - 1] == s[n - 3]) {
if (s[n - 1] == 'L' && s[n - 2] == 'R') sayNo();
if (s[n - 1] == 'R' && s[n - 2] == 'L') sayNo();
if (s[n - 1] == 'U' && s[n - 2] == 'D') sayNo();
if (s[n - 1] == 'D' && s[n - 2] == 'U') sayNo();
}
d = 1;
int x = 0, y = 0;
vector <pii> ans;
for (int i = 0; i < n; i++) {
if (s[i] == 'R') {
x = d;
ans.push_back(MP(x + 1, y));
}
if (s[i] == 'L') {
x = -d;
ans.push_back(MP(x - 1, y));
}
if (s[i] == 'D') {
y = -d;
ans.push_back(MP(x, y - 1));
}
if (s[i] == 'U') {
y = d;
ans.push_back(MP(x, y + 1));
}
if (i + 1 < n) {
if (s[i] == 'L' && s[i + 1] == 'R') {}
else if (s[i] == 'R' && s[i + 1] == 'L') {}
else if (s[i] == 'U' && s[i + 1] == 'D') {}
else if (s[i] == 'D' && s[i + 1] == 'U') {}
else d += 2;
}
}
cout << -x << ' ' << -y << '\n';
sort(all(ans));
ans.erase(unique(all(ans)), ans.end());
cout << sz(ans) << '\n';
for (auto it : ans) {
cout << it.fi - x << ' ' << it.se - y << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
H. Hard Drive
貪心一下就行。
從后往前插入\(1\),我們首先想讓他貢獻\(2\)次,如果是偶數就很簡單,奇數會多一次我們插在\(1\)位置即可。
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/9 13:31:53
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
int n, c, b;
cin >> n >> c >> b;
vector <int> a(n, -1);
for (int i = 0; i < b; i++) {
int x; cin >> x; --x;
a[x] = 0;
}
int t = c / 2;
for (int i = n - 2; i >= 0 && t; i--) {
if (a[i] == -1) {
a[i] = 1;
--t; --i;
}
}
if (c & 1) {
a[0] = 1;
}
for (int i = 0; i < n; i++) {
if (a[i] == -1) a[i] = 0;
cout << a[i];
}
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
I. Inflation
簽到。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 2e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
const int N = 2e5,M = (1<<20);
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
ll ans=1;
for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
return ans;
}
mt19937 mrand(random_device{}());
int c[MAXN];
void run(){
int n; cin>>n;
rep(i,1,n)cin>>c[i];
sort(c+1,c+1+n);
db frac = 1;
rep(i,1,n){
if(c[i]>i){
cout<<"-1\n";
return ;
}
frac = min(frac,(db)c[i]/i);
}
printf("%.6f\n",frac);
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0);
int _=1;
while(_--)run();
return 0;
}
J. Jinxed Betting
假設當前除開第一個人其余分數最大值為\(MAX\),有\(cnt\)個。並且現在最大和次大的差值為\(d\)。
顯然模擬一下會發現經過\(log_2\lfloor\frac{cnt}{2}\rfloor\)次過后\(MAX\)會加一,並且再經過一次\(d\)會減少\(1\)。
也就是一個過程我們可以看作\(log_2\lfloor\frac{cnt}{2}\rfloor+1\)步,對於每一個值來說會重復\(d\)次,之后會更新\(MAX,cnt\)並且繼續執行以上操作直到\(MAX\)超過\(a[0]\)。
那么手動模擬一下這個過程即可,注意一下邊界的情況。
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/9 22:17:52
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <iomanip>
#include <assert.h>
#include <functional>
#include <numeric>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
#define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
void err() { std::cout << std::endl; }
template<typename T, typename...Args>
void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
template <template<typename...> class T, typename t, typename... A>
void err(const T <t> &arg, const A&... args) {
for (auto &v : arg) std::cout << v << ' '; err(args...); }
#else
#define dbg(...)
#endif
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
void run() {
int n; cin >> n;
vector <ll> a(n);
vector <int> lg(N);
lg[2] = 1;
for (int i = 3; i < N; i++) {
lg[i] = lg[i >> 1] + 1;
}
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(all(a));
reverse(all(a));
int t = 1;
ll ans = 0, Max = a[1];
while (1) {
while (t + 1 < n && a[t + 1] == a[t]) ++t;
if (t == n - 1) {
int k = lg[t];
ll D = a[0] - Max;
ll A = D / k;
Max += A * k;
ans += 1ll * (k + 1) * A;
ans += D % k;
break;
} else {
ll d = a[t] - a[t + 1];
int k = lg[t]; //+=k
if (1ll * k * d + Max <= a[0]) {
Max += 1ll * k * d;
ans += 1ll * (k + 1) * d;
} else {
ll D = a[0] - Max;
ll A = D / k;
Max += A * k;
ans += 1ll * (k + 1) * A;
ans += D % k;
break;
}
}
++t;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
run();
return 0;
}
K. Kleptography
簽到。
Code
#include<cstdio>
using namespace std;
char enc[107];
char orn[107];
int main() {
int n, m; scanf("%d%d", &n, &m);
scanf("%s%s", orn+m-n, enc);
for(int i=m-n-1, j=m-1; i>=0; i--, j--) {
orn[i]=(enc[j]-orn[j]+26)%26+'a';
}
printf("%s\n", orn);
}