Codeforces1609C Complex Market Analysis (思维)

题目链接: 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;
}

END

猜你喜欢

转载自blog.csdn.net/weixin_45799835/article/details/121637148