NC252710 Kevin喜欢零 (简单版本) (前缀积,二分)

在这里插入图片描述

在这里插入图片描述
这题给出了一个全新的做题方法:前缀积(说来也是,有前缀和那肯定也有前缀积啊)

首先读入后构建前缀积,然后把 1 1 1 ~ n n n 作为左端点,然后二分去搜靠左的右端点和靠右的右端点,这里的意义就是避免有连着的相同的积,可以构建出多个区间,比如样例中的:125 1 8 1 1,连续的1就可以导致这种局面。

搜完之后,再判断一下是不是能搜到一个答案,如果能搜到就加上靠右的右端点减去靠左的右端点加1.

#include<iostream>
using namespace std;
#define ll long long
const int N = 2e5 + 10;

ll a[N];	//开longlong存前缀积
int n, k;

int check(ll x) {		//返回后导0数量的函数
	ll res = 0;
	while (x % 10 == 0 && x) {	//注意两个判别条件
		x /= 10;				//1.x的最后一位是0	2.x没有变成0
		res++;
	}

	return res;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t; cin >> t;
	while (t--) {
		cin >> n >> k;

		a[0] = 1;	//a[0]设为1,便于建立前缀积
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			a[i] *= a[i - 1];	//读入并建立前缀积
		}

		ll ans = 0;//这里要开long long
		for (int i = 1; i <= n; i++) {	//枚举所有左端点

			int l = i, r = n;	
			while (l < r) {	//二分搜靠左的右端点
				int mid = (ll)l + r >> 1;
				if (check(a[mid] / a[i - 1]) >= k)r = mid;
				else l = mid + 1;
			}

			ll res = l;	//记录上端点

			l = i, r = n;
			while (l < r) {	//二分搜靠右的右端点
				int mid = (ll)l + r + 1 >> 1;
				if (check(a[mid] / a[i - 1]) <= k)l = mid;
				else r = mid - 1;
			}

			//如果i~右端点对应的前缀积后导0的个数是等于k的
			if (check(a[res] / a[i - 1]) == k)	//这里要判断,因为可能二分到最后没有答案
				ans += l - res + 1;	//答案加上两点相减
			//这里因为搜到的左和右两个端点到i的积是一样的,搜左右的意义就在于搜到那种连续相同积的情况
		}
		cout << ans << endl;
	}
	return 0;
}
  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值