将k从小到大排序,因为k越大对结果的影响越大,我们从大的k开始考虑。
我设置了flag变量来记录到当前时,需要多少个
p
a
[
i
]
p^{a[i]}
pa[i]才能让答案即差值为0.
显然贪心的策略是,不断去缩小这个差值。
当
f
l
a
g
=
=
0
flag==0
flag==0只能把答案加上当前
p
a
[
i
]
p^{a[i]}
pa[i].
如果
f
l
a
g
!
=
0
flag!=0
flag!=0显然要减去当前的值让答案减小。
但是如果存在两个相邻的k差值很大,那么这个需要的数量就会超出ll的范围。
我们要怎么规避呢?
注意到有一个特殊情况,即当flag>=i时无论如何都不可能让差值变成0了。
判断一下这个特殊情况是否条件成立,如果成立直接不断减去接下来的值让答案更小即可。
对于计数可能炸ll的情况,我通过在快速幂里传入标记判断是否答案经过了取模.
是否取模对这种特殊情况的判断有一点小不同,但是都是对flag>=i的判定。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAXN 1000005
int a[MAXN];
const int mod=1000000007;
ll qpow(ll a,ll b,int *flag)
{
ll res=1;
int cnt=0;
while(b)
{
if(b&1) {
res = res * a;
*flag|=cnt;
}
if(res>=mod){
res%=mod;
*flag=1;
}
a=a*a;
if(a>=mod)
{
a%=mod;
cnt=1;
}
b>>=1;
}
return res;
}
int main()
{
int t;
cin>>t;
while(t--) {
int n, p;
scanf("%d%d", &n, &p);
for (int i=1;i<=n;i++)
scanf("%d",a+i);
sort(a+1,a+1+n);
ll del=0;
ll flag=0;
a[n+1]=a[n];
for(int i=n;i>=1;i--)
{
int boolean=0;
ll cmp=qpow(p,a[i+1]-a[i],&boolean);
if(boolean==0&&flag*cmp>=i||boolean&&flag)
{
while(i>=1)
del=(del-qpow(p,a[i],&boolean)+mod)%mod,i--;
break;
}
flag*=cmp;
if(flag==0){
flag++;
del=qpow(p,a[i],&boolean);
} else
{
flag--;
del=(del-qpow(p,a[i],&boolean)+mod)%mod;
}
}
cout<<del<<endl;
}
}