CF818E Card Game Again
题目大意
给定长为 的数列 ,求有多少对 满足 是 的约数。
解题思路
做法一
我会 二分 !!!
枚举左端点,然后去找满足条件的右端点。
首先将 分解质因数。
可以发现, 分解质因数后,只有和有 相同的质因数可以选上,否则对于答案是没有贡献的。
那么就可以将有用的质因数的个数用前缀和维护起来。
可以在 的时间复杂度内求出所有的对整除影响的质数有多少。
在这个区间内,若对于每个质数的个数均大于等于 分解后对应质数的个数,则代表这个区间可以整除 。
时间复杂度为 。
CODE
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
char c = getchar();
int x = 0, f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
#define int long long
#define mk(x, y) make_pair(x, y)
const int MAXN = 1e5 + 5;
vector<pair<int, int>> vec;
int a[MAXN], n, k;
int cnt[MAXN][50], ans;
bool Check(int l, int r)
{
for (int i = 0; i < vec.size(); i++)
if (cnt[r][i] - cnt[l - 1][i] < vec[i].second)
return 0;
return 1;
}
signed main()
{
n = read(), k = read();
a[n + 1] = k;
for (int i = 1; i <= n; i++)
a[i] = read();
for (int i = 2; i * i <= k; i++)
{
if (k % i == 0)
vec.push_back(mk(i, 0));
while (k % i == 0)
{
k /= i;
vec[vec.size() - 1].second++;
}
}
if (k != 1)
vec.push_back(mk(k, 1));
for (int i = 1; i <= n + 1; i++)
{
int tmp = a[i];
for (int j = 0; j < vec.size(); j++)
{
cnt[i][j] = cnt[i - 1][j];
while (tmp % vec[j].first == 0)
{
tmp /= vec[j].first;
cnt[i][j]++;
}
}
}
for (int i = 1; i <= n; i++)
{
int l = i, r = n + 1, as = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (Check(i, mid))
r = mid - 1, as = mid;
else
l = mid + 1;
}
ans += n - as + 1;
}
printf("%lld\n", ans);
return 0;
}
做法二
我会乱推!!!
显然,如果有一个区间 中间的所有数乘积能被 整除,则对于一个 的一切区间 ,里面所有数的乘积一定都能被 整除。
那么我们只需要找出所有的 最小合法区间 即可。
从 进行前缀乘积,每次模上 ,只要遇到一个合法区间,也就是前缀乘积为 ,这时候从这个点立刻回头,从后往前找出这个区间的左端点,找到的区间肯定是最短的。
另外,要避免重复的情况,当开始搜下一个新的区间时候,应当把起始点重置为之前找到的右端点 。
时间复杂度 。
CODE
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int _ = 1e5 + 5;
inline int read()
{
char c = getchar();
int x = 0, f = 1;
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n, k;
int a[_];
int now = 1, l = 1, r;
int ans;
signed main()
{
n = read();
k = read();
for (int i = 1; i <= n; ++i)
{
a[i] = read();
now = now * a[i] % k;
if (!now)
{
now = 1;
for (r = i; now * a[r] % k; r--)
now = now * a[r] % k;
ans += (n - i + 1) * (r - l + 1);
l = r + 1;
}
}
printf("%lld\n", ans);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122089