題目傳送門
題意:
給你長度爲 的正整數序列
,一個正整數
。
讓你統計滿足區間的積與和的商等於 的區間個數。
數據範圍: 。
題解:
區間計數,先考慮一下 。
發現不會轉移。那應該就是優美的暴力了。
觀察發現如果一直乘的話幾十個就不可能再符合要求了,只需要特殊考慮 這個數字。
在一段連續的 中,因爲乘積是不變的,和是遞增的,所以商是遞減的,這段區間的貢獻不超過
。
所以預處理每個數最近的下一個不是 的位置就好了。
感受:
學會了判斷溢出。
世上的題都是套路題,一種是你見過的套路,一種是你沒見過的套路。
代碼:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 2e5 + 5 ;
int n ;
ll k , a[maxn] ;
int nxt[maxn] ;
void init()
{
nxt[n + 1] = n + 1 ;
for(int i = n ; i >= 1 ; i --)
{
if(a[i] > 1) nxt[i] = i ;
else nxt[i] = nxt[i + 1] ;
}
}
bool boom(ll x , ll y)
{
return x > LLONG_MAX / y ;
}
int solve(int i)
{
ll pro = a[i] , sum = a[i] ;
int ans = 0 ;
if(k == 1) ans ++ ;
for(int j = i + 1 ; j <= n ; j ++)
{
if(boom(pro , a[j])) return ans ;
if(a[j] > 1)
{
pro *= a[j] , sum += a[j] ;
if(pro % sum == 0 && pro / sum == k) ans ++ ;
}
else
{
int num = nxt[j] - j ;
if(pro % k == 0 && k * (sum + 1) <= pro && pro <= k * (sum + num))
ans ++ ;
sum += num ;
j = nxt[j] - 1 ;
}
}
return ans ;
}
int main()
{
int ans = 0 ;
scanf("%d%lld" , &n , &k) ;
for(int i = 1 ; i <= n ; i ++) scanf("%lld" , &a[i]) ;
init() ;
for(int i = 1 ; i <= n ; i ++)
ans += solve(i) ;
printf("%d\n" , ans) ;
return 0 ;
}