2020杭电多校第三场 1004 Tokitsukaze and Multiple

Problem Description

Tokitsukaze has a sequence of length n, denoted by a.
Tokitsukaze can merge two consecutive elements of a as many times as she wants. After each operation, a new element that equals to the sum of the two old elements will replace them, and thus the length of a will be reduced by 1.
Tokitsukaze wants to know the maximum possible number of elements that are multiples of p she can get after doing some operations (or doing nothing) on the sequence a.
Input

There are several test cases.
The first line contains an integer T (1≤T≤20), denoting the number of test cases. Then follow all the test cases.
For each test case, the first line contains two integers n and p (1≤n,p≤105), denoting the length of the sequence and the special number, respectively.
The second line contains n integers, where the i-th integer ai (1≤ai≤105) is the i-th element of a.
It is guaranteed that the sum of n in all test cases is no larger than 106.
Output

For each test case, output in one line the maximum possible number of elements that are multiples of p after doing some operations.

样例输入

在这里插入代码片
2
5 3
2 1 3 2 1
3 1
123 456 789

样例输出
3
3

思路:

对输入的每个数对p取余,遍历数组,记录前面相加出现的结果,如果后面相加出现的结果x之前出现过,则前面出现x的位置到当前位置这个区间的和对p求余为0. 尽可能选择最先满足区间和对p取余的结果为0的区间,这样求出来的是最大的,如果区间的和为p倍数且其中的后缀跟后缀的后面几个数相加起来等于p的倍数,则应该选该区间而不是后面的那个区间,因为选择前面区间可以给后面的数字更多等于p的倍数的机会。

代码:

在这里插入代码片
#include <bits/stdc++.h>

#define ll long long
using namespace std;
int a[100001];
int vis[100001];
int cnt = 0,ans;
int main()
{
    ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);
    int t;
    cin>>t;
    while(t--){
        int n,p;
        cin>>n>>p;
		ans = 0;
		for(int i = 1;i <= n;i++){
			cin>>a[i];
			a[i]=a[i]%p;
		}
		cnt++;
		ll sum = 0;  
		//用cnt来区别是否是已经消去了的区间
		//a...b...c...d
		//假设ab区间内相加的和为p的倍数且里面的前缀和用vis记录且设为1
		//消去之后如果cnt没有+1,则后面ad区间中的某一段包括ab部分和cd中的一部分加起来为p的倍数
		//但是之前消去了就会导致误认为没消去 如果cnt不加1的话
		for(int i = 1;i <= n;i++){
			sum += a[i];
			sum %= p;
			if(vis[sum] == cnt || sum == 0){
				ans++;
				sum = 0;
				cnt++;
			}
			else
			vis[sum] = cnt;
		}
		cout<<ans<<endl;

    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值