Codeforces Round #717 (Div. 2) D. Cut
Posted TURNINING
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #717 (Div. 2) D. Cut相关的知识,希望对你有一定的参考价值。
题意:数组有n个数,有q次询问,每次询问给你一个区间l,r,问[l, r]最少的划分次数是多少。划分的规则为:每个划分后的区间每个数都互质。
思路:对于每次询问,要想划分次数最少显然我们得贪心的令子区间的长度最长。求子区间的最长长度思路很简单,从i开始一直往后遍历一直到gcd不为1为止(互质)。现在我们就可以得到以i开头,最长的划分区间了。对于每次询问我们就可以直接算次数了。但我们能直接暴力的算次数吗?显然不行,当每个数都为1时可以把我们卡上天。那怎么办? 倍增
现在我们思路都已经很清楚了,那么怎么求每个数的最长区间呢?(n^2暴力求肯定不行的吧?) 对于这种区间有限制的贪心问题,考虑双指针,这样我们就可以尽可能的减少移动次数。设双指针左右区间为l, r当加上arr[r]后若公共素数最大值为1(求公共素数最大值我套了个线段树)那么我们就移动右指针,大于1就说明l最长右点就是r-1(为什么是r-1,因为我们每次都会把r+1),到此问题就全部解决了。这个双指针我没想到,我好菜。。。。
#include<bits/stdc++.h>
using namespace std;
#define lsn (u << 1)
#define rsn (u << 1 | 1)
#define mid (l + r >> 1)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<double, double> PD;
const int MAXN = 1e5 + 10;
const int MAX_LEN = 100000 + 10;
const int MAX_LOG_V = 22;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-7;
const ull B = 100000007;
int n, q;
int arr[MAXN];
int nxt[MAXN];
int f[MAXN][21];
int tr[4*MAXN];
void pushup(int u) { tr[u] = max(tr[lsn], tr[rsn]); }
void add(int u, int l, int r, int p, int v) {
if(l == r && l == p) tr[u] += v;
else {
if(p <= mid) add(lsn, l, mid, p, v);
else add(rsn, mid+1, r, p, v);
pushup(u);
}
}
void add(int x) {
int last = -1;
while(x > 1) {
if(nxt[x] != last) {
add(1, 1, 1e5, nxt[x], 1);
last = nxt[x];
}
x /= nxt[x];
}
}
void del(int x) {
int last = -1;
while(x > 1) {
if(nxt[x] != last) {
add(1, 1, 1e5, nxt[x], -1);
last = nxt[x];
}
x /= nxt[x];
}
}
void solve() {
scanf("%d %d", &n, &q);
for(int i = 1; i <= n; i++) scanf("%d", &arr[i]);
int r = 1;
for(int i = 1; i <= n; i++) {
while(r <= n && tr[1] < 2) {
add(arr[r++]);
}
f[i][0] = r - 1;
if(tr[1] < 2 && r == n + 1) f[i][0] = n + 1;
del(arr[i]);
}
for(int k = 0; k < 20; k++) {
for(int i = 1; i <= n; i++) {
if(f[i][k] == n+1) f[i][k+1] = n+1;
else f[i][k+1] = f[f[i][k]][k];
}
}
for(int i = 1; i <= q; i++) {
int l, r; scanf("%d %d", &l, &r);
int ans = 0;
for(int k = 20; k >= 0; k--) {
if(f[l][k] <= r) {
l = f[l][k];
ans += (1 << k);
}
}
printf("%d\\n", ans + 1);
}
}
int main() {
//ios::sync_with_stdio(false);
for(int i = 2; i < MAXN; i++) {
if(!nxt[i]) {
for(int j = i; j < MAXN; j += i) {
nxt[j] = i;
}
}
}
int t = 1; //scanf("%d", &t);
while(t--) {
solve();
}
return 0;
}
以上是关于Codeforces Round #717 (Div. 2) D. Cut的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #717 (Div. 2)-A. Tit for Tat-题解
区间倍增dpD. Cut——Codeforces Round #717 (Div. 2)
Codeforces Round #717 (Div. 2)-C. Baby Ehab Partitions Again-题解
Codeforces Round #717 (Div. 2)-B. Maximum Cost Deletion-题解
Codeforces Round #717 (Div. 2)-B. Maximum Cost Deletion-题解
Codeforces Round #717 (Div. 2)-C. Baby Ehab Partitions Again-题解