- Contest Info
- Solutions
- A. Access Points
- B. Brexit Negotiations
- E. Equality Control
- G. Game Design
- H. Hard Drive
- I. Inflation
- J. Jinxed Betting
- K. Kleptography
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。
问最后最小的贡献为多少。
思路:
- 一条边的贡献为\((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
#include
#include
#include
#include
#include
#include
#include
B. Brexit Negotiations
拓扑序+贪心。
从前往后贪心正确性得不到保障,但是从后往前即可解决这一问题。
很有意思,拓扑序有时候反着来就能解决很多问题QAQ。
代码写着较为复杂。。
Code
#include
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
#define vi vector
#define vii vector>
#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
inline void cmin(T &a,T b){a = min(a,b);}
template
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, 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<
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
#include
#include
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
#include
#include
H. Hard Drive
贪心一下就行。
从后往前插入\(1\),我们首先想让他贡献\(2\)次,如果是偶数就很简单,奇数会多一次我们插在\(1\)位置即可。
Code
/*
* Author: heyuhhh
* Created Time: 2020/6/9 13:31:53
*/
#include
#include
#include
#include
#include
#include
#include
#include
I. Inflation
签到。
Code
#include
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
#define vi vector
#define vii vector>
#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
inline void cmin(T &a,T b){a = min(a,b);}
template
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
#include
#include
#include
#include
#include
#include
#include
K. Kleptography
签到。
Code
#include
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);
}