根号分治
-
根号分治是一种思想,一般根据一个数(可以是数组的数,也可以是答案的数)分类,分为大于 s q r t ( n ) sqrt(n) sqrt(n)的部分和小于等于 s q r t ( n ) sqrt(n) sqrt(n)的部分
-
题目链接: luogu.com.cn/problem/P3396
-
解题思路: 根号分治的经典题目。我们根据模数分类,模数大于等于 s q r t ( n ) sqrt(n) sqrt(n)的部分我们暴力求解,小于等于的部分我们提前预处理出来就好了
const int N = 2e5 + 5;
int n , m , a[N];
int dp[N][405];
int main ()
{
CLOSE;
cin >> n >> m;
for (int i = 1 ; i <= n ; i ++)
cin >> a[i];
int p = sqrt (n);
for (int i = 1 ; i <= n ; i ++)
{
for (int j = 1 ; j <= p ; j ++)
dp[j][i%j] += a[i];
}
while (m --)
{
string op;
int x, y;
cin >> op >> x >> y;
if (op == "A")
{
if (x <= p) cout << dp[x][y] << endl;
else
{
ll ans = 0;
for (int j = y ; j <= n ; j += x)
ans += a[j];
cout << ans << endl;
}
}
else
{
for (int j = 1 ; j <= p ; j ++)
dp[j][x%j] += (y-a[x]);
a[x] = y;
}
}
}
- 题目链接: https://codeforces.com/problemset/problem/1446/D2
- 解题思路: 本题与简单版本的差异在于出现数的种类,那么我们按每个数出现的次数根号分治,那么出现次数大于等于 s q r t ( n ) sqrt(n) sqrt(n)的数种类一定是不超过 s q r t ( n ) sqrt(n) sqrt(n)那么这一部分我们可以和 E e s y Eesy Eesy部分同样处理,接下来是出现次数小于等于 s q r t ( n ) sqrt(n) sqrt(n)的这一部分。显然我们也需要根据 s q r t ( n ) sqrt(n) sqrt(n)这个复杂度来。所以,我们枚举最终序列中最大出现次数为 x x x, x x x属于 [ 1 , s q r t ( n ) ] [1,sqrt(n)] [1,sqrt(n)]。接下来可以利用尺取得做法求出每个 x x x得最大值
const int N = 2e5 + 5;
int n , buck[N], a[N];
int mx, val, cnt;
int ans = 0;
unordered_map <int,int> ma;
void solve1 (int x)
{
ma.clear();
int v = 0;
ma[0] = 0;
for (int i = 1 ; i <= n ; i ++)
{
if (a[i] == x) v ++;
if (a[i] == val) v --;
if (!ma.count(v))
ma[v] = i;
else
ans = max (ans , i - ma[v]);
}
}
void solve2 (int x)
{
for (int i = 1 ; i <= n ; i ++) buck[i] = 0;
int l = 1, type = 0;
buck[a[l]] ++;
if (buck[a[l]] == x) type ++;
for (int i = 2 ; i <= n ; i ++)
{
buck[a[i]] ++;
if (buck[a[i]] == x) type ++;
else if (buck[a[i]] > x)
{
if (buck[a[i]] == x + 1) type --;
while (buck[a[i]] > x)
{
buck[a[l]] --;
if (buck[a[l]] == x) type ++;
else if (buck[a[l]] == x - 1) type --;
l ++;
}
}
if (type >= 2) ans = max (ans, i - l + 1);
}
}
int main ()
{
CLOSE;
cin >> n;
mx = 0, val = 0, cnt = 0;
for (int i = 1 ; i <= n ; i ++) {
cin >> a[i], buck[a[i]]++;
if (buck[a[i]] > mx)
mx = buck[a[i]], val = a[i], cnt = 1;
else if (buck[a[i]] == mx)
cnt ++;
}
if (cnt > 2)
{
cout << n << endl;
return 0;
}
int limit = sqrt (n);
for (int i = 1 ; i <= n ; i ++)
if (buck[i] >= limit && i != val)
solve1 (i);
for (int i = 1 ; i < limit ; i ++)
solve2 (i);
cout << ans << endl;
}