省选模拟19/10/29

在这里插入图片描述
对于横边和竖边分别考虑
如果是横边,那么斜率 k k k 的范围在 [ x r , x l ] [\frac{x}{r},\frac{x}{l}] [rx,lx]
如果是竖边,那么范围在 [ l x , r x ] [\frac{l}{x},\frac{r}{x}] [xl,xr]
然后问题就变为了给一些区间,求覆盖一个点的区间权值最小的,这里的权值是 x , y x,y x,y 坐标
线段树即可,标记永久化,正解处理区间用的假分数离散化,不过暴力 d o u b l e double double 精度好像不会被卡
另外对于 x , y x,y x,y 0 0 0 的情况需要特判
如果 x x x 为 0,只考虑横边
如果 y y y 为 0,只考虑竖边

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt * 10 + (ch - '0'), ch = getchar();
	return cnt * f;
}
cs int N = 1e5 + 5;
int n;
struct node{
	int opt, idx, val; // 0 -> x, 1 -> y, 2 -> query 
	double l, r;
}q[N << 1]; int ret;
double b[N << 2]; int siz;
typedef pair<int,int> pi;
#define mp make_pair
#define fi first
#define se second
pi ck(pi a, pi b){
	if(a.fi == b.fi) return a.se > b.se ? a : b; // 覆盖之前的  
	return a.fi < b.fi ? a : b;
}
cs int inf = 1e9 + 7;
struct segmentree{
	pi tg[N << 4];
	#define mid ((l+r)>>1)
	void build(int x, int l, int r){
		tg[x] = mp(inf, 0); if(l == r) return;
		build(x<<1, l, mid); build(x<<1|1, mid+1, r);
	}
	void modify(int x, int l, int r, int L, int R, pi v){
		if(L<=l && r<=R){ tg[x] = ck(tg[x], v); return; } 
		if(L<=mid) modify(x<<1, l, mid, L, R, v);
		if(R>mid) modify(x<<1|1, mid+1, r, L, R, v);
	}
	pi query(int x, int l, int r, int p){
		if(l == r) return tg[x]; 
		if(p <= mid) return ck(tg[x], query(x<<1, l, mid, p));
		else return ck(tg[x], query(x<<1|1, mid+1, r, p));
	}
}seg[2];
int main(){
	freopen("raytracing.in","r", stdin);
	freopen("raytracing.out","w",stdout);
	n = read();
	for(int i = 1; i <= n; i++){
		int opt = read();
		if(opt == 1){
			int x0 = read(), y0 = read(), x1 = read(), y1 = read();
			if(x0 == 0){
				q[++ret] = (node){1, i, y0, 1.0 * y0 / x1, inf}; // y 
				b[++siz] = q[ret].l; // 只能交在 y 方向  
				b[++siz] = q[ret].r;
			}
			else if(y0 == 0){
				q[++ret] = (node){0, i, x0, 1.0 * y0 / x0, 1.0 * y1 / x0}; // x
				b[++siz] = q[ret].l; // 只能交在 x 方向  
				b[++siz] = q[ret].r;
			}
			else{
				q[++ret] = (node){0, i, x0, 1.0 * y0 / x0, 1.0 * y1 / x0}; // x
				q[++ret] = (node){1, i, y0, 1.0 * y0 / x1, 1.0 * y0 / x0}; // y
				b[++siz] = q[ret - 1].l;
				b[++siz] = q[ret - 1].r; 
				b[++siz] = q[ret].l;
				b[++siz] = q[ret].r;
			}
		}
		if(opt == 2){
			int x = read(), y = read();
			if(x == 0) q[++ret] = (node){2, i, 0, inf, 0};
			else q[++ret] = (node){2, i, 0, 1.0 * y / x, 0};
			b[++siz] = q[ret].l;
		}
	}
	sort(b + 1, b + siz + 1); siz = unique(b + 1, b + siz + 1) - (b + 1);
	seg[0].build(1, 1, siz); seg[1].build(1, 1, siz);
	for(int i = 1; i <= ret; i++){
		int opt = q[i].opt;
		if(opt ^ 2){
			int l = lower_bound(b + 1, b + siz + 1, q[i].l) - b;
			int r = lower_bound(b + 1, b + siz + 1, q[i].r) - b;
			seg[opt].modify(1, 1, siz, l, r, mp(q[i].val, q[i].idx));
		}
		else{
			int p = lower_bound(b + 1, b + siz + 1, q[i].l) - b;
			pi fx = seg[0].query(1, 1, siz, p);
			pi fy = seg[1].query(1, 1, siz, p);
			int ans = 0;
			if(!fx.se || !fy.se) { cout << fx.se + fy.se << '\n'; continue;}
			if(q[i].l == 0) ans = fx.se;
			else if(q[i].l == inf) ans = fy.se;
			else{
				double k1 = fx.fi * q[i].l, k2 = fy.fi;
				if(k1 == k2) ans = max(fx.se, fy.se);
				else if(k1 < k2) ans = fx.se;
				else ans = fy.se;
			} cout << ans << '\n';
		}
	} return 0;
}

N个雪人,每个雪人都有一个可爱度Xi,WZY认为两串雪人 a 1 , a 2 … a n a_1,a_2…a_n a1,a2an b 1 , b 2 … b m b_1,b_2…b_m b1,b2bm和谐当且仅当
n = m n=m n=m a 1 − b 1 = a 2 − b 2 = … = a n − b n a_1-b_1=a_2-b_2=…=a_n-b_n a1b1=a2b2==anbn
现在要从一堆雪人中选择两串雪人 A = [ l 1 , r 1 ] , B = [ l 2 , r 2 ] A=[l1,r1],B=[l2,r2] A=[l1,r1],B=[l2,r2],使得A和B和谐,现在WZY想知道对于所有的方案中, m i n ( ∣ l 1 − l 2 ∣ , l e n ( A ) ) min(|l1-l2|,len(A)) min(l1l2,len(A))的最大值
首先差分一下变成类似字符串匹配的问题
做法繁多:
法1:二分答案,问题转换为找到两个后缀,使得 l c p ≥ l e n lcp\ge len lcplen,并且它们的出现位置 i − j ≥ l e n i-j\ge len ijlen
求出 h e i g h t height height过后满足 l c p ≥ l e n lcp\ge len lcplen 的就是很多个区间,区间求一个 m i n , m a x min,max min,max 判断即可
也可以 h a s h hash hash,把长度为 l e n len len h a s h hash hash 取出来,排序,相同的一坨求 m i n , m a x min,max min,max 即可
法2:直接上后缀自动机,对于每一个结点考虑,对 R i g h t Right Right 集合求一个 m i n , m a x min,max min,max,那么可以用 m i n ( m a x − m i n , l e n ) min(max-min,len) min(maxmin,len) 来更新答案

#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt * 10 + (ch - '0'), ch = getchar();
	return cnt * f;
}
cs int N = 5e5 + 5;
int n, m, siz, a[N], d[N], b[N], lg[N], ans = 1;
struct SAFFIX{
	int sa[N], rk[N], y[N], c[N], tp[N], hi[N];
	int st[N][20];
	void Sort(){
		for(int i = 0; i <= m; i++) c[i] = 0;
		for(int i = 1; i <= n; i++) c[rk[i]]++;
		for(int i = 1; i <= m; i++) c[i] += c[i-1];
		for(int i = n; i >= 1; i--) sa[c[rk[y[i]]]--] = y[i];
	}
	void SA(){
		for(int i = 1; i <= n; i++) y[i] = i, rk[i] = d[i]; Sort();
		for(int k = 1; k <= n; k <<= 1){
			int ret = 0;
			for(int i = n - k + 1; i <= n; i++) y[++ret] = i;
			for(int i = 1; i <= n; i++) if(sa[i] > k) y[++ret] = sa[i] - k;
			Sort(); swap(rk, tp); rk[sa[1]] = 1; int cnt = 1;
			for(int i = 2; i <= n; i++){
				if(tp[sa[i]] == tp[sa[i-1]] && tp[sa[i] + k] == tp[sa[i-1] + k])
					rk[sa[i]] = cnt;
				else rk[sa[i]] = ++cnt;
			} m = cnt;
		}
	}
	void Hi(){
		int k = 0;
		for(int i = 1; i <= n; i++){
			if(rk[i] == 1) continue;
			int j = sa[rk[i] - 1]; if(k) k--;
			while(i + k <= n && j + k <= n && d[i + k] == d[j + k]) k++;
			hi[rk[i]] = k;
		}
		for(int i = 1; i <= n; i++) st[i][0] = hi[i];
		for(int j = 1; (1 << j) <= n; j++)
			for(int i = 1; i + (1 << j) - 1 <= n; i++)
				st[i][j] = min(st[i][j - 1], st[i + (1<<j-1)][j - 1]);
	}
	int LCP(int i, int j){
		int l = rk[i], r = rk[j];
		if(l > r) swap(l, r); ++l;
		int x = lg[r - l + 1];
		return min(st[l][x], st[r - (1<<x) + 1][x]);
	}
}T;
bool check(int len){
	int mx = 0, mi = 0;
	for(int i = 2; i <= n; i++){
		if(T.hi[i] < len) {mx = mi = 0; continue; }
		if(T.hi[i-1] < len){
			mx = max(T.sa[i], T.sa[i - 1]);
			mi = min(T.sa[i], T.sa[i - 1]);
			if(mx - mi >= len) return true; 
			continue;
		}
		mx = max(mx, T.sa[i]);
		mi = min(mi, T.sa[i]);
		if(mx - mi >= len) return true;
	} return false;
}
void Solve(){
	int l = 1, r = n; 
	while(l < r){
		int mid = (l+r+1) >> 1;
		if(check(mid)) l = mid; 
		else r = mid - 1;
	} ans = max(ans, l + 1);
}
int main(){
	n = read();
	for(int i = 2; i <= n; i++) lg[i] = lg[i>>1] + 1;
	for(int i = 1; i <= n; i++) a[i] = read();
	for(int i = 1; i < n; i++) d[i] = a[i + 1] - a[i], b[++siz] = d[i];
	sort(b + 1, b + siz + 1); siz = unique(b + 1, b + siz + 1) - (b + 1);
	for(int i = 1; i < n; i++) d[i] = lower_bound(b + 1, b + siz + 1, d[i]) - b;
	--n; 
	m = siz; T.SA(); T.Hi();
	Solve(); cout << ans;
	return 0;
}
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt * 10 + (ch - '0'), ch = getchar();
	return cnt * f;
}
cs int N = 1e6 + 5;
int n, m, siz, a[N], d[N], b[N], ans = 1;
namespace SAM{
	int las, node;
	void init(){ las = node = 1; }
	map<int, int> ch[N]; int lk[N], len[N], ps[N];
	int a[N], c[N];
	int mx[N], mi[N];
	void extend(int c, int k){
		int now = ++node, p = las; len[now] = len[p] + 1; ps[now] = k;
		for(;p && !ch[p][c]; p = lk[p]) ch[p][c] = now;
		if(!p) lk[now] = 1;
		else{
			int q = ch[p][c]; 
			if(len[q] == len[p] + 1) lk[now] = q;
			else{
				int cl = ++node; len[cl] = len[p] + 1; 
				lk[cl] = lk[q]; ch[cl] = ch[q]; 
				lk[now] = lk[q] = cl;
				for(;p && ch[p][c] == q; p = lk[p]) ch[p][c] = cl;
			}
		} las = now;
	}
	void Solve(){
		for(int i = 1; i <= node; i++) c[len[i]]++;
		for(int i = 1; i <= n; i++) c[i] += c[i-1];
		for(int i = node; i >= 1; i--) a[c[len[i]]--] = i;
		memset(mi, 0x3f, sizeof(mi));
		for(int i = node; i >= 1; i--){
			int x = a[i];
			mx[x] = max(mx[x], ps[x]);
			mi[x] = min(mi[x], ps[x]);
			mx[lk[x]] = max(mx[lk[x]], mx[x]);
			mi[lk[x]] = min(mi[lk[x]], mi[x]);
			ans = max(ans, min(len[x] + 1, mx[x] - mi[x] + 1));
		}
	}
}
int main(){
	n = read();
	for(int i = 1; i <= n; i++) a[i] = read();
	for(int i = 1; i < n; i++) d[i] = a[i + 1] - a[i], b[++siz] = d[i];
	sort(b + 1, b + siz + 1); siz = unique(b + 1, b + siz + 1) - (b + 1);
	for(int i = 1; i < n; i++) d[i] = lower_bound(b + 1, b + siz + 1, d[i]) - b;
	n--; SAM::init();
	for(int i = 1; i <= n; i++) SAM::extend(d[i], i);
	SAM::Solve(); cout << ans;
	return 0;
}

LOJ6078. 「2017 山东一轮集训 Day7」重排
首先对于一个没有自环的 S − D A G S-DAG SDAG,比较容易求出答案
f i f_i fi 表示到终点的期望长度, w i w_i wi 表示边权
考虑一个点的出边与它对面的点,不妨设为 m , n m,n m,n 个,那么每次一定选择 w j + f v w_j+f_v wj+fv 最小的那个走
也就是说 f u = 1 p ! m i n ( w j + f v ) f_u=\frac{1}{p!}min(w_j+f_v) fu=p!1min(wj+fv)
发现本质不同的 w j + f v w_j+f_v wj+fv 只有 n m nm nm
f u = ∑ i ∑ j ( w j + f v ) ∗ 它 作 为 最 小 值 的 概 率 f_u=\sum_{i}\sum_{j}(w_j+f_v)*它作为最小值的概率 fu=ij(wj+fv)
如何算概率,对于这 n m nm nm 个点排序,然后一个点最小当且仅当它之前的都不取,用一个堆每次取队头即可
然后最头疼的是有环的情况
我们令 f i f_i fi 表示到终点的期望,但是 f i f_i fi 可以由 f i f_i fi 自己转移
我们考虑二分迭代,先钦定 f i f_i fi m i d mid mid
然后把 f i f_i fi 代进去算出 f i f_i fi 的答案跟 m i d mid mid 比较,如果大了就把下届调它
不能证明这样一定能找到最优解


#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt * 10 + (ch - '0'), ch = getchar();
	return cnt * f;
}
cs int N = 1e3 + 5;
cs double eps = 1e-8;
int n, m, S, T;
double E[N];
int first[N], nxt[N], to[N], tot; double w[N];
void add(int x, int y, double z){
	nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z;
} 
bool vis[N], toT[N];
double a[N], b[N]; int ps[N];
struct node{
	int v; double w;
	bool operator < (cs node &a) cs{ return w > a.w;}
}; int ct;
double calc(){
	priority_queue<node> q;
	for(int i = 1; i <= ct; i++) q.push((node){i, a[i] + b[1]}), ps[i] = ct;
	double p = 1, res = 0;
	while(!q.empty() && p > 0){
		node t = q.top(); q.pop();
		int v = t.v; double w = t.w;
		double tmp = 1.0 * p * (ps[v] - v) / (ps[v] - v + 1.0);
		--ps[v]; res += w * (p - tmp); p = tmp;
		if(ps[v] >= 1) q.push((node){v, a[v] + b[ct - ps[v] + 1]});
	} return res;
}
void dfs(int u){
	vis[u] = true; bool Self = false;
	if(u == T){ toT[u] = true; return; }
	for(int e = first[u]; e; e = nxt[e]){
		 if(!vis[to[e]]) dfs(to[e]);
		 toT[u] |= toT[to[e]];
	} if(!toT[u]){ E[u] = 1e10; return;}
	ct = 0; 
	for(int e = first[u]; e; e = nxt[e]){
		a[++ct] = w[e]; Self |= to[e] == u;
	} sort(a + 1, a + ct + 1);
	if(!Self){
		ct = 0; for(int e = first[u]; e; e = nxt[e]) b[++ct] = E[to[e]];
		sort(b + 1, b + ct + 1); E[u] = calc(); return;
	}
	double l = 0, r = 1e6;
	while(l + eps < r){
		E[u] = (l + r) * 0.5;
		ct = 0; for(int e = first[u]; e; e = nxt[e]) b[++ct] = E[to[e]];
		sort(b + 1, b + ct + 1); calc() > E[u] ? l = E[u] : r = E[u];
	} E[u] = l;
}
int main(){
	n = read(), m = read(), S = read(), T = read();
	for(int i = 1; i <= m; i++){
		int x = read(), y = read(); double z; scanf("%lf", &z);
		add(x, y, z); 
	}
	dfs(S); if(!toT[S]) puts("-1");
	else printf("%.8lf", E[S]); return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可 6私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值