Johnny and Grandmaster
或許更好的閱讀體驗
思路
這道題就是把一組數分成兩個集合,使這兩個集合的對p的次方的和的差的最小值,也就是求得最小值, 由於結果過大我們可能需要對結果取模。那麼這題得關鍵在於我們應該如何分配這兩個集合,也就是如何得到最優的的值。
我們先把給定的數組從大到小排序,我們一定可以得到,這一點是顯然成立的。
我們先分配最大的數到集合中,接下來我們再分配其他的數到集合,中,直到,我們再重新分配一個數到集合中,重複如此操作我們就可以的到最小值。
這題的關鍵就在於我們如何判斷這兩個集合中的數和是相等的,容易想到,於是我們好像可以利用這個點來完美的實現這個算法,但是很遺憾,wa在了test7,這裏可能存在一個極大的誤差,當我們的剛好是模數的時候,顯然這裏就錯了,所以我們必須選定一個方法來避免這個錯誤,於是就有了,雙模數判定差值是否爲0。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return f * x;
}
const int mod = 1e9 + 7, MOD = 1e9 + 3;//用兩個模數來判斷是否爲零,
const int N = 1e6 + 10;
ll a[N];
ll qpow(ll a, ll n, ll mod) {
ll ans = 1;
while(n) {
if(n & 1) ans = (ans * a) % mod;
a = (a * a) % mod;
n >>= 1;
}
return ans;
}
int main() {
// freopen("in.txt", "r", stdin);
int t = read();
while(t--) {
int n = read(); ll p = read();
for(int i = 1; i <= n; i++)
a[i] = read();
sort(a + 1, a + 1 + n, greater<ll> ());
char *str = "okkkk";
ll ans1 = 0, ans2 = 0;
for(int i = 1; i <= n; i++) {
if(!ans1 && !ans2) {//當這兩個數同時爲零的時候代表兩個集合的差值爲零。
ans1 = (ans1 + qpow(p, a[i], mod)) % mod;
ans2 = (ans2 + qpow(p, a[i], MOD)) % MOD;
}
else {
ans1 = (ans1 + mod - qpow(p, a[i], mod)) % mod;
ans2 = (ans2 + MOD - qpow(p, a[i], MOD)) % MOD;
}
}
printf("%lld\n", ans1);
}
return 0;
}