宝乐很喜欢末尾数位上是0的数字,如果一个数末尾至少有k个0我们就称其为完美数。现在有一个长度为n的数组,如果一个子区间的所有数字之积是完美数,那么我们就称该区间为完美区间。宝乐想知道该数组有多少完美区间,聪明的你帮忙解决这个问题吧。
本题子区间的定义:原始序列或集合中的一段连续的子集,其中元素之间的顺序保持不变。
输入一行两个整数n,k,分别代表数组大小和完美数末尾的0的个数。
接下来一行包含 n 个整数 1<=n<=2e5 1<=k<=2e6 1<=ai<=1e9;
输入 3 1 10 20 30 输出6
输入 3 1 1 2 3 输出 0;
这个题是我们以前没有见过的类型的题,虽然说是用到了前缀和,但是如果只用前缀和那一定是过不了这一题的,所以我们在比赛的时候就直接忽略了暴力求解。那么该用什么方法解决这一题呢。要用到一点的思维,题目问有几个0 我们知道2*5=10,所以这题的求解是一定和2 5有关的。把2 5看成一个组合,有几个组合就有几个0 例如2 * 5 * 2有一个组合,所以有一个0。例如2*5*5*2有两个组合就有两个0。因此我们就要求出来一个数里面有几个2,几个5,将找0的任务转换成找2 5,在输入的时候就可以边输入边找有几个2 5;重新定义两个专门的数组来存储ai里面2和5的个数令为a2和a5数组,然后再定义它们的前缀和数组b2和b5来判断。附上代码
#include <bits/stdc++.h>
#define int long long//开long long
using namespace std;
const int N =2e5+5;
int a[N],a2[N],a5[N],b2[N],b5[N];
void check(int x,int i)//这个函数是用来找ai里面有几个2 几个5
{
int t=x;
while (x%2==0) {
a2[i]++;x/=2;
}
while (t%5==0) {
a5[i]++;t/=5;
}
}
void solve ()
{
int n,k;cin>>n>>k;int ans=0;
for (int i=1;i<=n;i++) {
cin>>a[i];check(a[i],i);
}//边输入进来边给a2,a5数组放东西,放的就是有几个2 几个5
for (int i=1;i<=n;i++) {
b2[i]=b2[i-1]+a2[i];
b5[i]=b5[i-1]+a5[i];
}//再用前缀和给数组处理一下,因为是一个区间所以我们要用到前缀和
for (int i=1;i<=n;i++) {//典型的遍历数组找区间,每个区间都逃不掉
for (int j=i;j<=n;j++) {
int t2=b2[j]-b2[i-1];
int t5=b5[j]-b5[i-1];//这两步找t的值是看看有几个2 和 5
int sum=min(t2,t5);//这步是关键,前面也说到了看有几个组合才有几个0,2和5谁出现的次数少就有几个组合
if (sum>=k) {
ans+=n-j+1;break;//这里ans+=n-j+1是因为只要我前面相乘符合有k个0,后面就一定也有k个0,break掉节约时间
}
}
}
cout<<ans;//最后输出ans就可以得到答案
}
signed main ()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
while (T--) solve ();
return 0;
}
这题对于我来说还是挺难的,比赛的时候是肯定想不到的,毕竟这是第一次遇到这样类型的题。看了学长们的题解才勉强搞懂。路漫漫其修远兮,吾将上下而求索。