正睿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

posted @ 2018-09-03 09:50  zzzzx  阅读(196)  评论(0编辑  收藏  举报