这道题的思路来源于一个叫zbr的大佬 真的挺秒的 仔细想想也不是很难 但是没有想到如此简便的做法
首先我们要从大到小排序 这个应该没问题 因为大数的权重远远比小的大 所以先分配大的在分配小的
其次 我们要清楚 对于一个大数 如果我们把他分配给一个集合 另外一个集合就要想办法凑出这个数 根据p^k这个特殊性 假设我们这个一个大数是 p^k 那么比它小的数 要么刚好凑成它 要么不够凑 这是显然易见的 如果不够凑 答案就是 p^k减去所有比它小的数 否则 我们把p^k 凑出来 在重置差值为0 再继续这个过程 具体可以代码 注意差值为0的时候 不能光用当前值来判断 得再搞一个模数 这样可以保证 差值为0 (否则你的差值为mod的倍数 求出来也是0) 类似双hash
具体看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//两个模数
const ll mod1=1000000007;
const ll mod2=983231753;
ll qpow(ll a,ll b,ll mod){
ll ret = 1;
while(b){
if(b&1) ret=(ret%mod*a%mod)%mod;
a=(a%mod*a%mod)%mod;
b>>=1;
}
return ret;
}
const int N = 1e6+10;
ll a[N];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,p;
scanf("%d%d",&n,&p);
ll ans=0,ans1=0;
for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
//降序排列
sort(a+1,a+1+n);
reverse(a+1,a+1+n);
for(int i = 1; i <= n; i++){
ll temp=qpow(p,a[i],mod1),temp1=qpow(p,a[i],mod2);
//当差值为0的时候 我们把大数分配给一个集合
if(ans==0&&ans1==0) ans=temp,ans1=temp1;
//当差值不为0,我们去凑那个大数(只有刚好凑出和不够两种情况) 凑一个减一个
else ans=(ans-temp+mod1)%mod1,ans1=(ans1-temp1+mod2)%mod2;
}
printf("%lld\n",ans);
}
return 0;
}