D Empty Graph
感觉是被题目绕晕了,再回顾下题目
a
l
a_l
al 与
a
r
a_r
ar 之间的距离为
m
i
n
(
a
i
)
min(a_i)
min(ai)
(
i
∈
[
l
,
r
]
)
(i∈[l,r])
(i∈[l,r])
a
l
a_l
al 与
a
r
a_r
ar 之间的最短距离为图的一条路径
而图的直径为所有路径中最长的
我们要使图的直径最长
贪心没想好,我们选择二分答案
那么问题转换成如何
c
h
e
c
k
check
check 答案
我们选择的
l
l
l
r
r
r 距离越远
m
i
n
(
a
i
)
min(a_i)
min(ai) 越小
所以我们可以直接考虑相邻点的最短距离
而最短距离为
m
i
n
(
m
a
x
(
a
l
,
a
r
)
,
m
i
n
(
a
i
)
∗
2
)
min(max(a_l,a_r),min(a_i)*2)
min(max(al,ar),min(ai)∗2)
我们直接枚举
1
1
1 到
n
n
n 使每个不满足
a
i
∗
2
<
m
i
d
a_i*2<mid
ai∗2<mid的
a
i
a_i
ai 设为
1
e
9
1e9
1e9
同时如果
m
a
x
(
a
l
,
a
r
)
<
m
i
d
max(a_l,a_r)<mid
max(al,ar)<mid 那么我们进行分类讨论
如果在此之前我们已经修改了一个值,那么直接在该值旁白再修改一个
1
e
9
1e9
1e9 即可
否则如果此时的最大值满足
m
a
x
(
a
i
)
≥
m
i
d
max(a_i)≥mid
max(ai)≥mid,同理也只需修改一个值即可
否则就需要修改两个值
最后判断
s
u
m
<
=
k
sum<=k
sum<=k 即可
s
u
m
sum
sum 为累积的修改次数
ps:
弄清题意永远比急着写题重要,已经吃了无数次亏了
在真正明白题意后,然后在写之前滤清思路能大幅增加写代码的效率,并且减少
b
u
g
bug
bug的产生,多耗费一点时间是完全值得的
int n, m, k, ma;
int a[N], b[N];
bool check(ll da)
{
rep(i, 1, n) b[i] = a[i];
int cnt = 0;
rep(i, 1, n) if (b[i] * 2 < da) b[i] = 1e9, cnt++;
bool ok = false;
rep(i, 2, n) if (min(b[i], b[i - 1]) >= da) { ok = true; break; }
if (!ok)
{
if (cnt) cnt++;
else if (ma >= da) cnt++;
else cnt += 2;
}
return cnt <= k;
}
void solve()
{
cin >> n >> k;
ma = 0;
rep(i, 1, n) cin >> a[i], ma = max(ma, a[i]);
ll l = 0, r = 1e9, mid;
while (l < r)
{
mid = (l + r + 1) >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
}
E2 LCM Sum
显然该题要离线做
首先
l
c
m
(
i
,
j
,
k
)
≥
3
k
lcm(i,j,k)≥3k
lcm(i,j,k)≥3k是肯定可以的
那我们只需要考虑
l
c
m
(
i
,
j
,
k
)
=
2
k
lcm(i,j,k)=2k
lcm(i,j,k)=2k 和
l
c
m
(
i
,
j
,
k
)
=
k
lcm(i,j,k)=k
lcm(i,j,k)=k
1.
l
c
m
(
i
,
j
,
k
)
=
2
k
1.lcm(i,j,k) = 2k
1.lcm(i,j,k)=2k
我们列几个例子发现只有
(
3
,
4
,
6
)
(3,4,6)
(3,4,6) 和
(
6
,
10
,
15
)
(6,10,15)
(6,10,15) 及其倍数不符合条件
(其实这能证明的,但是我懒)
2.
l
c
m
(
i
,
j
,
k
)
=
k
2.lcm(i,j,k)=k
2.lcm(i,j,k)=k
设
k
k
k 有
p
p
p 个因数,那么就有
C
p
2
C_p^2
Cp2 个组合不符合条件
我们先存储所有的询问,并对每个区间左端点排序
我们先预处理所有
i
i
i 的倍数
x
x
x 存在
v
e
c
t
o
r
<
i
n
t
>
p
[
x
]
vector<int>p[x]
vector<int>p[x] 中,复杂度
O
(
n
l
o
g
l
o
g
n
)
O(nloglogn)
O(nloglogn)
然后从
1
1
1 到
200000
200000
200000 扫描,统计每个
i
i
i 对其倍数
x
x
x 的贡献
将其累加到树状数组
T
.
s
[
x
]
T.s[x]
T.s[x] 中,并且对超出范围的
i
i
i 减去它的贡献
然后对
1
1
1 到
q
[
i
]
.
r
q[i].r
q[i].r 树状数组求和即可
vc<int> p[N];
void get_prime()
{
rep(i, 1, 200000)
for (int j = i * 2; j <= 200000; j += i)
p[i].pb(j);
}
void init()
{
// cin >> T_T;
get_prime();
}
int n;
ll ans[N];
struct P
{
int l, r, id;
bool operator<(const P &a)
{
return l < a.l;
}
}q[N];
struct FW_Tree
{
int n = 200000;ll s[N]={0};
void init(){rep(i,1,n)s[i]=0;}
void build(ll a[],int len)
{n=len;rep(i,1,n){s[i]+=a[i];if(i+lowbit(i)<=n)s[i+lowbit(i)]+=s[i];}}
void add(int i,ll x){for(;i<=n;i+=lowbit(i))s[i]+=x;}
void add(int l,int r,ll k){add(l,k),add(r+1,-k);}
ll ask(int i){ll ret=0;for(;i;i-=lowbit(i))ret+=s[i];return ret;}
ll ask(int l,int r){return ask(r)-ask(l-1);}
}T;
int f[N];
void solve()
{
cin >> n;
rep(i, 1, n) cin >> q[i].l >> q[i].r, q[i].id = i;
rep(i, 1, n)
{
ll len = q[i].r - q[i].l + 1;
ans[i] = len * (len - 1) / 2 * (len - 2) / 3;
ans[i] -= max(0, q[i].r / 6 - (q[i].l - 1) / 3);
ans[i] -= max(0, q[i].r / 15 - (q[i].l - 1) / 6);
}
sort(q + 1, q + n + 1);
int l = q[1].l, r = q[1].l - 1;
rep(i, 1, n)
{
while (r < q[i].r)
{
r++;
for (auto x : p[r]) T.add(x, f[x]++);
}
while (l < q[i].l)
{
for (auto x : p[l]) T.add(x, -(--f[x]));
l++;
}
ans[q[i].id] -= T.ask(q[i].r);
}
rep(i, 1, n) cout << ans[i] << endl;
}