codeforces992D 2100分暴力

題目傳送門

題意:

給你長度爲 n 的正整數序列 a ,一個正整數 k 。

讓你統計滿足區間的積與和的商等於 k 的區間個數。

數據範圍:1 \leqslant n\leqslant 2 \cdot 10^5 \;,1 \leqslant k \leqslant 10^5 , 1 \leqslant a_i \leqslant 10^8 。

題解:

區間計數,先考慮一下 dp 。

發現不會轉移。那應該就是優美的暴力了。

觀察發現如果一直乘的話幾十個就不可能再符合要求了,只需要特殊考慮 1 這個數字。

在一段連續的 1 中,因爲乘積是不變的,和是遞增的,所以商是遞減的,這段區間的貢獻不超過 1 。

所以預處理每個數最近的下一個不是 1 的位置就好了。

感受:

學會了判斷溢出。

世上的題都是套路題,一種是你見過的套路,一種是你沒見過的套路。

代碼:

#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 ;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章