Codeforces Round #813 (Div. 2)D,E
D. Empty Graph
题意
一张 \(n(2\le n\le 10^5)\) 个节点的无向完全图,有一个长为 \(n\) 的正整数序列 \(a\) ,边 \((l,r)\) 的权值为 \(\min(a_{l},a_{l+1},\ldots,a_{r})\) 。可以进行至多 \(k(1\le k\le n)\) 次操作,每次操作选择 \(a\) 中的一个数变为任意的正整数 \(x(1\le x\le10^9)\) 。求操作后能够得到的图的直径的最大值,图的直径为任意两点最短路的最大值。
思路
考虑两点 \((l,r)\) 间最短路在序列上的构成,首先可以直接沿着两点连边走,这部分显然为边权,其次可以通过其他点中转,容易发现,只有经过一个序列中值最小的点再走到目的地是另一个可能的最小值,有了这个性质后,还可以发现,直径一定是 \(i\) 到 \(i+1\) 的最短路,因为如果区间扩大,中转的部分是固定的,而直接走的这一部分一定不会变得更大。于是我们可以二分答案,对所有的 \(i,i+1\) 。检查是否能够在 \(k\) 次操作内使其最短路 \(>\) 当前检查的值,根据性质我们可以 \(O(n)\) 进行 \(\texttt{check}\) 。复杂度 \(O(nlogn)\) 。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
#define int LL
//#define double LD
#define lc tr[x].ch[0]
#define rc tr[x].ch[1]
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-10;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 100010;
int T, N, K, A[maxn];
bool check(int x)
{
int tmp = INF;
int cnt = 0;
for (int i = 1; i <= N; i++)
{
if (2LL * A[i] < x)
cnt++;
}
for (int i = 2; i <= N; i++)
{
int now = cnt;
if (2LL * A[i] >= x && A[i] < x)
now++;
if (2LL * A[i - 1] >= x && A[i - 1] < x)
now++;
tmp = min(tmp, now);
}
return tmp <= K;
}
void solve()
{
int lo = -1, hi = 1e9 + 1;
while (hi - lo > 1)
{
int mid = (hi + lo) / 2;
if (check(mid))
lo = mid;
else
hi = mid;
}
cout << lo << endl;
}
signed main()
{
IOS;
cin >> T;
while (T--)
{
cin >> N >> K;
for (int i = 1; i <= N; i++)
cin >> A[i];
solve();
}
return 0;
}
E. LCM Sum
\(\texttt{easy version}\)
题意
\(t(1\le t\le5)\) 次询问,每次询问 \(l,r(1\le l\le r\le2\cdot10^5)\) ,求 \([l,r]\) 内有多少三元组 \((i,j,k)(l\le i<j<k\le r)\) 满足 \(lcm(i,j,k)\ge i+j+k\)。
思路
考虑用总和减去不满足要求的三元组数目,由于 \(k<i+j+k<3k\) 。所以不满足的三元组的 \(lcm\) 只可能为 \(k\) 或者 \(2k\) (此时还需要 \(i+j>k\) )。于是 \(i,j\) 都必须为 \(2k\) 的约数,于是我们可以预处理出每个数的约数之后枚举 \(k\) 。对于每个 \(k\) 再暴力枚举所有为 \(2k\) 约数的 \((i,j)\) ,之后暴力判断即可,实现精细一点可以通过 \(\texttt{easy version}\) 。
代码
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
//#define int LL
//#define double LD
#define lc tr[x].ch[0]
#define rc tr[x].ch[1]
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-10;
const double pi = acos(-1);
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 200010;
LL T, L, R;
vector<LL>d[maxn * 2];
void solve()
{
LL N = R - L + 1, ans = N * (N - 1) * (N - 2) / 6LL;
for (LL k = L + 2; k <= R; k++)
{
int s = lower_bound(all(d[k * 2]), L) - d[k * 2].begin();
int t = upper_bound(all(d[k * 2]), k - 2) - d[k * 2].begin();
int nt = upper_bound(all(d[k * 2]), k - 1) - d[k * 2].begin();
for (int i = s; i < t; i++)
{
if (k % d[k * 2][i] == 0)
{
for (int j = i + 1; j < nt; j++)
{
if (d[k * 2][j] > k - 1)
break;
if (k % d[k * 2][j] == 0)
ans--;
else if (d[k * 2][i] + d[k * 2][j] > k)
ans--;
}
}
else
{
int ns = upper_bound(all(d[k * 2]), k - d[k * 2][i]) - d[k * 2].begin();
ans -= nt - max(i + 1, ns);
}
}
}
cout << ans << endl;
}
int main()
{
IOS;
for (LL i = 1; i <= 400000; i++)
{
for (LL j = i; j <= 400000; j += i)
d[j].push_back(i);
}
cin >> T;
while (T--)
{
cin >> L >> R;
solve();
}
return 0;
}
\(\texttt{hard version}\)
\(t\) 的限制变为 \(1\le t\le10^5\)
思路
代码
\(\texttt{TBD}\)