好数组——尺取法

好数组

给定一个长度为 n 的数组 a,计算数组 a 中所有子数组中好数组的数目。

好数组定义如下:

对于数组 al ,al+1, ⋯ ,ar ,若数组中所有数的质因数种类数不超过 k,则称为好数组。

Input

输入的第一行包含两个正整数 n,k (1≤k≤n≤10^5)

输入的第二行包含 n 个正整数 ai(1≤ ai ≤100)

Output

输出数组

a 中所有子数组中好数组的数目。

样例输入

4 2

2 6 5 15

样例输出

6

样例:

对于所有子数组:

2

2,6

2,6,5

2,6,5,15

6

6,5

6,5,15

5

5,15

15

k=2,所以除了 2,6,5,2,6,5,15,6,5,15,6,5 这四个子数组其他都是符合的。

解析:

尺取法:像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以说尺取法是一种高效的枚举区间的方法。

复制代码
#include <bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define int long long
priority_queue<int,vector<int>,greater<int>> ll;
priority_queue<int> rr;
typedef pair<int,int> PII;
const int N=1e5+10;
int n,k;
vector <int> prime[N];
int a[N];
map <int,int> q;
void get_prime(int n)
{
    int m=n;
    for (int i=2;i<=n/i;i++)
    {
        if (n%i==0)
        {
            prime[m].push_back(i);
            while (n%i==0) n /=i;
        }
    }
    if (n>1) prime[m].push_back(n);
}
signed main()
{
    ios;
    cin>>n>>k;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i];
        if (prime[a[i]].size()==0) get_prime(a[i]);
    }
    int cnt=0;
    for (int r=1,l=1;r<=n;r++)
    {
        for (int i=0;i<prime[a[r]].size();i++) q[prime[a[r]][i]]++;    
        while (q.size()>k)             //当种类数大于 k 时,就从当前 l 开始,减去a[l]的质数,直到种类数小于等于 k 为止
        {   
            for (int i=0;i<prime[a[l]].size();i++) 
            {
                q[prime[a[l]][i]]--;
                if (q[prime[a[l]][i]]==0) q.erase(prime[a[l]][i]);
            }
            l++;
        }
        cnt +=r-l+1;
    }
    cout<<cnt;
    return 0;
}
相关推荐
INGNIGHT24 分钟前
1908 · 布尔表达式求值(stack单调栈&dfs)
开发语言·c++·算法
lucas_AI41 分钟前
把表格压成 64 个 token,长文档问答反而更准了:先找表,再看数
人工智能·深度学习·算法
Zzz 小生1 小时前
Lazy Theta*:把昂贵的视线检测留到“真正需要”时再做
人工智能·算法·贪心算法·推荐算法
l1258652 小时前
# LangGraph Deep Research Agent 全流程设计:多轮研究、人机协同与真实来源管理
数据库·人工智能·python·算法·自然语言处理·oracle·langchain
青少儿编程课堂2 小时前
图形化编程实战:智能交通灯调度台,一个作品讲透循环、条件与广播
c++·python·算法·bfs·信息学竞赛
evans在进步2 小时前
LeetCode 438 找到字符串中所有字母异位词:滑动窗口与排序解法详解
算法·leetcode·职场和发展
M78佐菲2 小时前
Linux多线程:创建、回收与互斥同步
linux·笔记·学习·算法
小手cool2 小时前
使用递归对数组进行反转操作
java·数据结构·算法
兔兔兔兔13 小时前
记录C++ 13
开发语言·c++·算法
码行山野赴时序归途3 小时前
从暴力到最优:三道 C 语言入门题的解法思路
c语言·开发语言·数据结构·算法·leetcode·排序算法