先上题的链接 link
看了大佬的思路后,决定写文章记录一下。
这是大佬的题解 link
题意:
t组输入(惯用套路),输入n,x,再输入n个数(先记为a数组)。
开始操作:
(从数组第一个数到最后一个数)
如果a[i] % x == 0,那么将x个(a[i] / x)甩入数组末尾;
如果a[i] % x != 0,那么结束操作。
输出操作后数组a中所有数字的和。
思路:
刚开始用队列写的,一直卡在第5个测试点(不太聪明的亚子)
举个例子:
假设数组只有16这个数,x = 2
0: 16
1: 16 (8 8)
2: 16 (8 8) 4 4
3: 16 (8 8) (4 4 4 4)
4: 16 (8 8) (4 4 4 4) 2 2
··· ···
7: 16 (8 8) (4 4 4 4) (2 2 2 2 2 2 2 2)
··· ···
15: 16 (8 8) (4 4 4 4) (2 2 2 2 2 2 2 2) (1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 )
------------结束
最后的和就是5个16相加,换句话来说就是16最多可以被24整除,再算上自己本身,那么这个5就可以由4+1得来。
那么复杂一点的话,将数组变成4 2 16呢(x仍为2)
0: 4 2 16
1: 4 2 16 (2 2)
2: 4 2 16 (2 2) (1 1)
3: 4 2 16 (2 2) (1 1) (8 8)
4: 4 2 16 (2 2) (1 1) (8 8) 1 1
5: 4 2 16 (2 2) (1 1) (8 8) (1 1 1 1)
------------结束
可以发现结束操作在哪个数 取决于初始时能整除x的次数最少的那个数,将此次数记为cnt。
在这个例子中cnt = 1,而结束操作时 追溯到最根本是初始时的2,最终数组有(2 + 1)个4,(1 + 1)个2,(1 + 1)个16
即(cnt + 1 + 1)个4,(cnt + 1)个2,(cnt + 1)个16
斜体的“+ 1”表示自己本身,在2之前的数做了cnt + 1次的操作,在2包括2之后的数做了cnt次的操作。
就是说 找到数组中整除x的次数最少的数字,并记录该次数cnt和该数的位置p
最终答案就是a[i] * (cnt + 1 + 1) + a[j] * (cnt + 1)。 (其中0 <= i < p, p <= j < n)
上AC代码!!
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
ll a[N];
int main()
{
int t;
cin >> t;
while(t --)
{
ll n, x;
cin >> n >> x;
ll y, p, cnt = 1e5;
for (ll i = 0; i < n; i ++ )
{
cin >> a[i];
y = 0;
for (ll j = x; ; j *= x) //找每个数能整除x几次
if(a[i] % j == 0) y ++;
else break;
if(y < cnt) p = i, cnt = y;
}
ll sum = 0;
for (ll i = 0; i < p; i ++ ) sum += (cnt + 2) * a[i];
for (ll i = p; i < n; i ++ ) sum += (cnt + 1) * a[i];
cout << sum << endl;
}
return 0;
}