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
", 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
", a[2] / (2 + a[2] / r));
}
C Cheating Nim
实际上题目就是要求选择一些 (a_ioplus(a_i-1)) 使得异或起来等于给定的数 (igoplus_{i=1}^n a_i)。
然后发现 (xoplus(x-1)=2 ext{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
", ans);
}
D Dice Game
假设 Petr 以 (x) 的概率选红骰子,(1-x) 的概率选蓝骰子。那么 tourist 获胜的概率应当是 (sum_{i=1}^6max{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 ightarrow t) 有运水的时候连边 ((s,t))。
显然每个连通块之间不互相影响。所以对每个连通块分别考虑。
设 (n,A,B) 分别表示当前连通块的点数、每个点的水量之和、每条边的代价之和。
然后就可以发现只要 dfs 一遍生成树就可以使最小值 (gefrac{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
", f[lim-1]);
}
G FESTIVAL
FESTIVA(LLL...LLL)FESTIVA(LLL...LLL)....
设这些组分别有 (c_0,c_1,cdots) 个 L,则对应答案为 (sum c_iinom{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');
}
}