对于横边和竖边分别考虑
如果是横边,那么斜率
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,a2…an与
b
1
,
b
2
…
b
m
b_1,b_2…b_m
b1,b2…bm和谐当且仅当
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
a1−b1=a2−b2=…=an−bn
现在要从一堆雪人中选择两串雪人
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(∣l1−l2∣,len(A))的最大值
首先差分一下变成类似字符串匹配的问题
做法繁多:
法1:二分答案,问题转换为找到两个后缀,使得
l
c
p
≥
l
e
n
lcp\ge len
lcp≥len,并且它们的出现位置
i
−
j
≥
l
e
n
i-j\ge len
i−j≥len
求出
h
e
i
g
h
t
height
height过后满足
l
c
p
≥
l
e
n
lcp\ge len
lcp≥len 的就是很多个区间,区间求一个
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(max−min,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
S−DAG,比较容易求出答案
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=∑i∑j(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;
}