CODE FESTIVAL 2016 Grand Final【杂题】

A 1D Matching

贪心从左往右匹配,只要保证每个坐标的贡献系数正确即可。

时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef long long LL;
const int N = 200003, mod = 1e9 + 7;
int read(){
	int ch = getchar(), x = 0; bool f = false;
	for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0'; 
	return f ? -x : x;
}
int n, now, ans = 1;
pair<int, int> a[N];
int main(){
	n = read();
	for(int i = 0;i < (n<<1);++ i)
		a[i] = MP(read(), i<n);
	sort(a, a+(n<<1));
	for(int i = 0;i < (n<<1);++ i)
		if(a[i].se){
			if(now < 0) ans = LL(-now) * ans % mod;
			++ now;
		} else {
			if(now > 0) ans = LL(now) * ans % mod;
			-- now;
		}
	printf("%d\n", ans);
}

B Inscribed Bicycle

数学题,谔谔谔谔。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int x0, y0, x1, y1, x2, y2;
	scanf("%d%d%d%d%d%d", &x0, &y0, &x1, &y1, &x2, &y2);
	x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0;
	int S = abs(x1*y2-x2*y1);
	double a[3] = {sqrt(x1*x1+y1*y1), sqrt(x2*x2+y2*y2), sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))};
	sort(a, a + 3);
	double r = S / (a[0] + a[1] + a[2]);
	printf("%.12lf\n", a[2] / (2 + a[2] / r));
}

C Cheating Nim

实际上题目就是要求选择一些 \(a_i\oplus(a_i-1)\) 使得异或起来等于给定的数 \(\bigoplus_{i=1}^n a_i\)

然后发现 \(x\oplus(x-1)=2\text{lowbit}(x)-1\) 一定是 \(2^k-1\) 的形式。所以异或方案是唯一的。

#include<bits/stdc++.h>
using namespace std;
int n, x, sum, ans;
bool vis[30];
int main(){
	scanf("%d", &n);
	for(int i = 1;i <= n;++ i){
		scanf("%d", &x);
		sum ^= x;
		vis[__builtin_ctz(x)] = true;
	}
	for(int i = 29;~i;-- i)
		if(sum>>i&1){
			if(!vis[i]) return puts("-1"), 0;
			sum ^= (1<<i+1)-1; ++ ans;
		}
	printf("%d\n", ans);
}

D Dice Game

假设 Petr 以 \(x\) 的概率选红骰子,\(1-x\) 的概率选蓝骰子。那么 tourist 获胜的概率应当是 \(\sum_{i=1}^6\max\{p_ix,q_i(1-x)\}\),那么 Petr 会取使该值最小的 \(x\)

那为什么 tourist 一定能选中 \(\max\) 呢,实际上因为博弈论基本定理,只要收益函数对双方分别满足一定的凹凸性,双方就会不约而同地选中均衡点。

#include<bits/stdc++.h>
using namespace std;
typedef double db;
const db eps = 1e-12;
db p[6], q[6];
db f(db x){
	db r = 0;
	for(int i = 0;i < 6;++ i)
		r += max(p[i]*x, q[i]*(1-x));
	return r;
}
int main(){
	for(int i = 0;i < 6;++ i) scanf("%lf", p+i), p[i] /= 100;
	for(int i = 0;i < 6;++ i) scanf("%lf", q+i), q[i] /= 100;
	db l = 0, r = 1;
	while(r - l > eps){
		db lm = l+(r-l)/3, rm = r-(r-l)/3;
		if(f(lm) < f(rm)) r = rm;
		else l = lm;
	}
	printf("%.12f", f(l));
}

E Water Distribution

一言不合就建图,当 \(s\rightarrow t\) 有运水的时候连边 \((s,t)\)

显然每个连通块之间不互相影响。所以对每个连通块分别考虑。

\(n,A,B\) 分别表示当前连通块的点数、每个点的水量之和、每条边的代价之和。

然后就可以发现只要 dfs 一遍生成树就可以使最小值 \(\ge\frac{A-B}n\),然后取错不优,所以直接按这个值算就行。

对每个点集跑最小生成树之后就可以子集 dp 了,时间复杂度 \(O(3^n+2^nn^2)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
const int N = 15, M = 105;
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
int n, m, k, lim, fa[N], x[N], y[N], a[N];
db f[1<<N];
struct Edge {
	int u, v; db w;
	bool operator < (const Edge &o) const {
		return w < o.w; 
	}
} e[M];
int getf(int x){return x == fa[x] ? x : fa[x] = getf(fa[x]);}
db dis(int a, int b){
	return sqrt(LL(x[a]-x[b])*(x[a]-x[b])+LL(y[a]-y[b])*(y[a]-y[b]));
}
int main(){
	scanf("%d", &n); lim = 1<<n;
	for(int i = 0;i < n;++ i)
		scanf("%d%d%d", x+i, y+i, a+i);
	for(int S = 1;S < lim;++ S){
		m = k = 0;
		for(int i = 0;i < n;++ i) if(S>>i&1){
			f[S] += a[i];
			fa[i] = i;
			++ k;
			for(int j = i+1;j < n;++ j) if(S>>j&1){
				e[m].u = i; e[m].v = j;
				e[m++].w = dis(i, j);
			}
		}
		sort(e, e + m);
		for(int i = 0, j = 1;i < m && j < k;++ i){
			int u = getf(e[i].u), v = getf(e[i].v);
			if(u != v){f[S] -= e[i].w; fa[u] = v; ++ j;}
		}
		f[S] /= k;
	}
	for(int S = 1;S < lim;++ S)
		for(int T = S&S-1;T;T = S&T-1)
			chmax(f[S], min(f[T], f[S^T]));
	printf("%.9lf\n", f[lim-1]);
}

G FESTIVAL

FESTIVA(LLL...LLL)FESTIVA(LLL...LLL)....

设这些组分别有 \(c_0,c_1,\cdots\) 个 L,则对应答案为 \(\sum c_i\binom{i+7}7\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 512;
LL k, f[N]; int c[N], mx;
int main(){
	scanf("%lld", &k);
	f[0] = 1;
	for(int i = 1;i < N;++ i) f[i] = f[i-1] * (i+7) / i;
	for(int i = N-1;~i;-- i)
		if(k >= f[i]){
			c[i] = k / f[i];
			if(!mx) mx = i;
			k %= f[i];
		}
	for(int i = 0;i <= mx;++ i){
		printf("FESTIVA");
		for(int j = 0;j < c[i];++ j)
			putchar('L');
	}
}
posted @ 2021-05-29 15:27  mizu164  阅读(101)  评论(0编辑  收藏  举报