题目链接: Complex Market Analysis
大致题意
给定一个长度为 n n n的序列 a a a. 给定间隔 k k k.
定义: f ( i , j ) f(i, j) f(i,j) 表示从位置 i i i开始, 选取元素 a i , a i + k , a i + 2 k , . . . , a i + j k a_i, a_{i + k}, a_{i + 2k}, ..., a_{i + jk} ai,ai+k,ai+2k,...,ai+jk , 满足选取的所有元素的乘积为一个质数.
问: 对于 i , j ∈ [ 1 , n ] i, j \in [1, n] i,j∈[1,n]. 符合条件的 ( i , j ) (i, j) (i,j)对有多少个
解题思路
思维
我们考虑对答案产生贡献的集合一定是: 包含一个质数和若干个1.
因此我们可以枚举每个质数位置考虑对答案的贡献.
对于每个质数位置, 我们分别向其左右遍历, 找到左右侧中连续 1 1 1的个数 l e f t , r i g h t left, right left,right.
那么当前位置对答案的贡献为: ( l e f t + 1 ) ∗ ( r i g h t + 1 ) − 1 (left + 1) * (right + 1) - 1 (left+1)∗(right+1)−1.
减去的 1 1 1为长度为 1 1 1的区间(只选择了这个质数本身).
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
/* 欧拉筛模版 */
bool vis[N];
int prime[N], ind;
void init(int n = N - 5) {
vis[1] = 1; // 注意vis[1]是否需要置为1
for (int i = 2; i <= n; ++i) {
if (!vis[i]) prime[++ind] = i;
for (int j = 1; prime[j] * i <= n; ++j) {
vis[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
}
}
}
int a[N];
int main()
{
init();
int t; cin >> t;
while (t--) {
int n, m; scanf("%d %d", &n, &m);
rep(i, n) scanf("%d", &a[i]);
ll res = 0;
rep(i, n) {
if (vis[a[i]]) continue;
int left = 1, right = 1;
for (int j = i - m; j >= 1; j -= m) {
if (a[j] == 1) left++;
else break;
}
for (int j = i + m; j <= n; j += m) {
if (a[j] == 1) right++;
else break;
}
res += 1ll * left * right - 1;
}
printf("%lld\n", res);
}
return 0;
}