codeforces1029D 2100分map

題目傳送門

題意:

給你 n 個數 a_i ,讓你挑兩個數,把這兩個數拼起來,例如 12 和 34 拼起來是 1234 。

問拼起來的數是 k 的倍數的方案數。認爲 a_i \;,a_j 和 a_j \;,a_i 是不同的方案。都滿足 i \neq j 。

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

題解:

我們挑選的其實是 (a_i * 10^{length(a_j)} \;\%\; k + a_j \;\%\; k) \;\%\; k = 0 。

位數比較小,可以預處理出來。

因此我們就枚舉 a_i * 10^{length(a_j)} \;\%\; k ,去尋找 a_j \;\%\; k = (k - a_i * 10^{length(a_j)} \;\%\; k) \;\%\;k 。

後面的是可以預處理出來的。

感受:

這道題 \dpi{150}set 和 \dpi{150}map 都能做。

假如用 \dpi{150}map ,那得先 count 判定存在還是不存在。

如果不存在就去索引,那會慢很多。

代碼:

#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 2e5 + 5 ;
int n , k , a[maxn] , num[maxn] ;
ll ten[maxn] ;
map<int , int> mp[15] ;
void init()
{
	for(int i = 1 ; i <= n ; i ++)
	{
		int x = a[i] ;
		while(x > 0)  x /= 10 , num[i] ++ ;
		if(mp[num[i]].count(a[i] % k))  mp[num[i]][a[i] % k] ++ ;
		else  mp[num[i]][a[i] % k] = 1 ;
	}
	ten[0] = 1 ;
	for(int i = 1 ; i <= 10 ; i ++)
	  ten[i] = ten[i - 1] * 10 % k ;
}
bool ok(int i)
{
	ll y = ll(a[i]) * ten[num[i]] % k ;
	y += a[i] , y %= k ;
	return y == 0 ;
}
int cal(int i , int j)
{
	ll x = a[i] ;
	int y ;
	int ans = 0 ;
	x = x * ten[j] % k ;
	y = k - (int) x ;
	y %= k ;
	if(mp[j].count(y))  ans += mp[j][y] ;
	return ans ;
}
void solve()
{
	ll ans = 0 ;
	for(int i = 1 ; i <= n ; i ++)
	  for(int j = 1 ; j <= 10 ; j ++)
	    ans += cal(i , j) ;	  
	for(int i = 1 ; i <= n ; i ++)
	  if(ok(i))  ans -- ;
	printf("%lld\n" , ans) ;
}
int main()
{
	scanf("%d%d" , &n , &k) ;
	for(int i = 1 ; i <= n ; i ++)  scanf("%d" , &a[i]) ;
	init() ;
	solve() ;
	return 0 ;
}

 

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