正睿2018.9.1提高2
A 单调栈/凸壳
题目链接
题解
对于二次函数提出一个x
对于剩下的直线维护一个
我们需要求出最大值上轮廓
单调栈求上凸壳就好了
code
#include<cstdio>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') { if(c == '-')f = -1;c = getchar();}
while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
return x * f;
}
const int maxn = 500007;
int n,q;
struct fuc {
int a,b;
} a[maxn],q1[maxn],q2[maxn];
bool cmp(fuc a,fuc b) {
return a.a == b.a ? a.b < b.b : a.a < b.a;
}
double cross(fuc a,fuc b) {
return (double) (b.b - a.b) / (a.a - b.a);
}
int tp1 = 0,tp2 = 0;
long long ans[maxn * 7];
void getcvx() {
std::sort(a + 1,a + n + 1,cmp);
for(int i = 1;i <= n;++ i) {
while(tp1 && q1[tp1].a == a[i].a) tp1 --;
while(tp1 > 1 && cross(a[i],q1[tp1]) <= cross(q1[tp1],q1[tp1 - 1]) ) tp1 --;
q1[++ tp1] = a[i];
}
for(int i = 1;i <= n;++ i) a[i].b = -a[i].b;
std::sort(a + 1,a + n + 1,cmp);
for(int i = 1;i <= n;++ i) {
while(tp2 && q2[tp2].a == a[i].a) tp2 --;
while(tp2 > 1 && cross(a[i],q2[tp2]) <= cross(q2[tp2],q2[tp2 - 1]) ) tp2 --;
q2[++ tp2] = a[i];
}
}
int main() {
n = read(); q = read();
for(int i = 1;i <= n;++ i) a[i].a = read(),a[i].b = read();
getcvx();
for(int i = 1,x = 1;i <= 32323;++ i) {
while(x < tp1 && cross(q1[x],q1[x + 1]) <= i) ++ x;
ans[i + 32323] = 1ll * q1[x].a * i * i + 1ll * q1[x].b * i;
}
for(int i = 1,x = 1;i <= 32323;++ i) {
while(x < tp2 && cross(q2[x],q2[x + 1]) <= i) ++ x;
ans[32323 - i] = 1ll * q2[x].a * i * i + 1ll * (q2[x].b) * i;
}
for(int i = 1;i <= q;i += 1) {
int k = read();
printf("%lld\n",ans[k + 32323]);
}
return 0;
}
B 概率/期望
题目链接
题解
答案可以看做是每一个元素被减的次数之和,可以计算每一个位置被减次数的期望之和
第一个元素一定被减了\(a_1\)次
考虑一个位置i,当前有n个元素,那每个元素被减的概率都是\(\frac{1}{c}\)。
只关注元素\(1\)和元素\(i\),发现操作其他元素对他们没有影响,被减的概率仍相同
于是这个问题等价于只有两个元素的问题
对于两个元素的问题,可以看为从\((a_1,a_i)\)出发,每次随机一个位置\(-1\),知道走到坐标轴上
若停留在\((0,a)\),对答案的贡献为\(a_i - a\),若停留在\((a,0)\),对答案的贡献为a_i
可以写出贡献式子
\[\sum_{i=0}^{a_i-1}\frac{\binom{a_1-1+i}{i}}{2^{a_1+i}}i+a_i\left(1-\sum_{i=0}^{a_i-1}\frac{\binom{a_1-1+i}{i}}{2^{a_1+i}}\right)
\]
可以对于\(0 - max(ai)\)做前缀和,前后的概率式等价,最后可以线性计算答案
code
#include<cstdio>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x * 10 + c - '0' ,c = getchar();
return x * f;
}
#define LL long long
const int mod = 323232323;
const int maxn = 200007;
int n,m,a1,a[maxn];
int inv[maxn],inv2[maxn];
int fac[maxn];
inline int fstpow(int x,int k) {
int ret = 1;
for(;k;k >>= 1,x = 1ll * x * x % mod) if(k & 1)ret = 1ll * ret * x % mod;
return ret;
}
inline int C(int n,int m) {
return (1ll * fac[n] * inv[m] % mod) * inv[n - m] % mod;
}
void pre() {
fac[1] = fac[0] = 1;
for(int i = 2;i <= m;++ i) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[m] = fstpow(fac[m],mod - 2);
for(int i = m - 1;~ i;-- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
//inv[2^i]
int t = fstpow(2,mod - 2); inv2[0] = 1;
for(int i = 1;i <= m;++ i) inv2[i] = 1ll * inv2[i - 1] * t % mod;
}
inline void add(int &x,int y) {
x = x + y >= mod ? x + y - mod : x + y;
}
int p[maxn],f[maxn];
int main() {
n = read();int mx = 0;
for(int i = 1;i <= n;++ i) a[i] = read(),mx = std::max(mx,a[i]);
a1 = a[1], m = a1 + mx;
pre();
p[0] = inv2[a1];
for(int i = 1;i <= m;++ i) {
p[i] = 1ll * C(a1 + i - 1,i) * inv2[a1 + i] % mod;
f[i] = 1ll * i * p[i] % mod;
add(p[i],p[i - 1]);
add(f[i],f[i - 1]);
}
int ans = a1;
for(int i = 2;i <= n;++ i) {
int t = (f[a[i]] + 1ll * a[i] * (mod + 1 - p[a[i]]) % mod) % mod;
add(ans,t);
}
printf("%d\n",ans);
return 0;
}
C
题目链接
题解
code