漂亮数组

链接:https://ac.nowcoder.com/acm/contest/67744/E


题目描述

阿宁认为一个数组是漂亮数组,该数组需要存在一个总和是kk的倍数的子数组。

现在阿宁有一个长度为nn的数组aa,阿宁想要将数组aa分割出若干个数组,分割出的数组需要满足,按照分割顺序合并可以得到原数组aa

阿宁想知道将数组aa分割,最多可以获得多少个漂亮数组?

输入描述:

第一行输入两个整数nnkk

第二行输入nn个整数aia_i

1n2×1051≤n≤2×10^5

1k,ai1091≤k,ai≤10^9

输出描述:

输出一个整数。

示例1

输入

text
1
2
6 3
1 1 4 5 1 4

输出

text
1
2

说明

分割成[1,1,4],[5,1],[4],其中[1,1,4],[5,1]两个数组是漂亮数组。


题解

首先,对于一个给定的数组,如果第aia_i个以前和第ai+2a_{i+2}个以后的都可以构成漂亮数组,那么我们来考虑一下将第ai+1a_{i+1}个数字放在前面还是后面。答案是后面,因为往前面这个数组里面再加入数字是没有意义的,不如留给下一个数组,这也就构成了我们这道题的思路:贪心。

接下看究竟什么样的数组才是漂亮数组。按题意,有两种情况:

第一种为数组的某一个子数组的和为kk的倍数。这是我们将数组分为两部分,由前面的贪心思想可知,前一部分为无关项,后一部分为相关项,即前半部分的和为bbb!=nkb!=nk,后半部分和为nknk,考虑到sum的结果可能超过long long的范围,所以我们考虑取余,并且可以通过前缀和来减少时间消耗。即当前缀和%k的余数之前已经出现过的时候,组成一最小的漂亮数组。

第二种是该数组的和恰好是kk的倍数,即前缀和%k的值为0。

下面是完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;
long long k;
long long a[200005]={0};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n>>k;
long long ans=0;
for (int i=1;i<=n;i++)
{
cin>>a[i];
a[i]=(a[i]+a[i-1])%k;
}
set <int > st;
int j=0;
for (int i=1;i<=n;i++)
{
if (st.find(a[i]-a[j]+k)!=st.end() || (a[i]-a[j])==0)
{
ans++;
j=i;
st.clear();
}
else
{
st.insert(a[i]-a[j]+k);
}
}
cout<<ans<<endl;
return 0;
}

漂亮数组
https://serendipity565.github.io/posts/114036b5cf38/
作者
Serendipity
发布于
2024年2月20日
许可协议
BY-SERENDIPITY565