B. Johnny and Grandmaster----------------------思维(贪心)

博客围绕将n个数分成两个集合A、B,使两集合差值绝对值最小的问题展开。解析中把pk[i]当成p进制下第k[i]位为1,按k[i]从大到小排序,通过将k[i]交替放入A、B集合来计算,同时考虑ans为MOD倍数出错的情况,需双模并用res变量记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

在这里插入图片描述
题意:
给定n个数和p,现在你需要将n个数分成两个集合A,B 使得两个集合差值绝对值最小
在这里插入图片描述

解析:
一贯的套路
我们把pk[i] 当成p进制下,第k[i]位为1.
那么就出现了一个性质 25 > 20 + 21 + 22 + 23 +24

所以我们按照k[i] 从大到小排
第一步找到最大的k[i] ,ans+=pk[i] 相当于把k[i] 放到A集合中
第二步 ans-=pk[i] 相当于把k[i]放到B集合中, 直到ans=0 再回到第一步去即可

最后还有一个问题,就是ans=0 。如果ans是MOD的倍数的话,就会出错。
所以需要双模 再用一个res变量记录 。 当res ==0 && ans == 0 才能回到第一步

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+1000;
const int MOD=1e9+7,mod=1e9+3;
ll a[N];
int t,n;
ll p;
ll quick(ll a,ll b,ll x)
{
    ll res=1%x;
    while(b)
    {
      if(b&1) res=res*a%x;
      a=a*a%x;
      b>>=1;
    }
    return res;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
      scanf("%d %lld",&n,&p);
      for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
      if(p==1){
        if(n&1) puts("1");
        else puts("0");
        continue;
      }
      sort(a+1,a+1+n,greater<int>());
      ll ans=0,res=0;
      for(int i=1;i<=n;i++)
      {
        if(!ans&&!res) ans=(ans+quick(p,a[i],MOD)),res=res+quick(p,a[i],mod);
        else{
          ans=((ans-quick(p,a[i],MOD))%MOD+MOD)%MOD;
          res=((res-quick(p,a[i],mod))%mod+mod)%mod;
        }

      }
      printf("%lld\n",ans);

    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值