ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

E. Johnny and Grandmaster

2020-06-05 23:08:23  阅读:384  来源: 互联网

标签:取模 Johnny int res ll 个数 Grandmaster MOD


E. Johnny and Grandmaster

题意:

​ 给定n个数\(P=\{p^{k_i} \}\),将这n个数划分到两个集合中,使得这两个集合的差值最小,求最小的差值对1e9+7取模。

思路:

​ 将n个数划分到两个集合可以转化为指定这n个数的正负性使得这n个数的和最小。

​ \(p^{k_i}\)可以看成是\(p\)进制表示的第\(k_i\)位为1,其余位为0的数,例如\(p=10,k=3\)时\(p^{k_i}=1000_{10}\)。按照这种表示方法可以想到,将这n个数按照从大到小的顺序排列,如果第一位取正,那么一定存在一个\(i\),使得第2到第\(i\)全部取负时,前\(i\)位的和位大于等于0,且\(i\)可以取得尽可能的大。意思就是,如果前\(i\)位的和大于零,且\(i<n\),那么\(i\)还可以扩大。

​ 例如,第一位为\(10^3\),第二位为\(10^2\),第三位为\(10^2\)....第\(j\)位为\(10\),这种情况,模拟一下就可以明白了。

\[\\p^{k_1}:1000_{p}\\p^{k_2}:100_{p}\\p^{k_3}:100_{p}\\p^{k_4}:100_{p}\\... \]

​ 更加普遍的规律,将这n个数按照从大到小排列后,如果第\(i\)位取正,那么一定存在一个\(j\),使得\(i+1\)到\(j\)全部取负,然后第\(i\)到\(j\)位的和大于等于0,且\(j\)可以取得尽可能的大。

​ 按照这种思路,很容易得出一个贪心策略,第一位取正,然后后面取负,直至和为0,然后再取一个正,后面的再取负,如此循环直至n个数全部用完,最后的和即为最小的。

​ 那么怎么证明呢?数学归纳法。

​ 只有一个数的时候,这种策略一定是正确的。

​ 假设有n个数的时候这种策略也是正确的。然后当有n+1个数的时候,使用这种策略给n+1个数指定正负,得出前n个数的和为\(sum_n\),记第n+1个数为\(arr_n\),如果\(sum_n==0\),则按照这种策略求得和为\(sum_{n+1}=arr_n\),如果\(sum_{n}>0\),则按照这种策略求得和为\(sum_{n+1}=sum_n-arr_n\)。

​ 假设存在一种最优策略求得和为\(best_{n+1}<sum_{n+1}\),记这种更优策略求得前n个数的和为\(best_{n}\)(如果\(best_n<0\),那么可以把最优策略规定的正负性取反得到等价策略,且\(best_n\ge0\)),根具数学归纳法的假设可以知到\(sum_n\le best_n\),即应对前n个数的时候贪心策略不比"最优策略“孬。又因为p进制数的缘故(重点),\(best_n>=arr_{n+1}\),所以最优策略在面对第n+1个数的时候会做和贪心策略等价的选择,这也就说明最优策略不会得到优于贪心策略的答案,即所谓的最优策略就是贪心策略。

​ 到这里我们已经知道为这n个数指定正负性的贪心策略,然后就是实现。

实现

​ 如果我们可以很简单的表示指数级的数,那么这题的实现就会很简单,但问题是我们表示不了,指数级的数不光会爆long long,且运算也耗时。那么该怎么办呢,想到题目中要求答案取模就可以了,那么我们是不是可以根据取模的性质在运算过程中实时的取模呢?

​ 答案并非那么简单。因为我们需要根据前面元素的和来决定当前位置的正负性,如果前面元素的和大于零,则当前元素取负,如果前面元素的和为零,则当前元素取正,然后修改这个和。这就产生了一个问题,取模会使得一个数变小,使得本来后面t个元素都负号,现在只能使一两个元素取负然后自身就变为零。

​ 那么该怎么办呢?注意到取模是对1e9+7取模,也就是只有我们的和大于这个值的时候才会真正的执行取模,而指数k的取值范围只有1e6那么点,那么我们可以从指数k入手。当算到当前元素的时候,实时计算前缀和是当前元素的多少!!倍!!,然后如果这个倍数需要取模大于1e9的时候,从此往后我们就无需判断是否为零,直接全部取负,因为后面最多1e6元素,而前缀和已经是其中最大值的1e9倍,那还判断什么呢。

tips

​ 与其说前缀和和当前元素的大小关系,不如说前缀和是当前元素的多少倍,从倍数这一概念入手可以更好的理解这题,且更符合进制这一概念。

垃圾代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1e6+10;
const ll MOD=1e9+7;
ll qpow(ll p,int q){
    ll res=1;
    while(q){
        if(q&1)res=res*p%MOD;
        q>>=1;
        p=p*p%MOD;
    }
    return res;
}
bool tpow(ll p,int q){
    ll res=1;
    while(q){
        if(q&1){
            res=res*p;
            if(res>=MOD)return 1;
        }
        q>>=1;
        p=p*p;
        if(p>=MOD&&q>0)return 1;
    }
    return 0;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        bool flag=0;
        int n,p;
        scanf("%d%d",&n,&p);
        vector<int>k;
        int temp;
        for(int i=0;i<n;i++){
            scanf("%d",&temp);
            k.push_back(temp);
        }
        sort(k.begin(),k.end());
        ll res=1;
        int prek=k.back();
        k.pop_back();
        int nowk;
        while(!k.empty()){
            nowk=k.back();
            k.pop_back();
            if(!flag) {
                if((tpow(p, prek - nowk)&&res!=0)||res*qpow(p,prek-nowk)>=MOD){
                    flag=1;
                    res=res*qpow(p,prek-nowk)%MOD;
                    res = (res - 1 + MOD) % MOD;
                }
                else {
                    res=res*qpow(p,prek-nowk);
                    if (res>0) {
                        res = res-1;
                    } else {
                        res = 1;
                    }
                }
            }
            else{
                res = res * qpow(p, prek - nowk) % MOD;
                res = (res - 1 + MOD) % MOD;
            }
            prek = nowk;
        }
        res=res*qpow(p,prek)%MOD;
        printf("%lld\n",res);
    }
    return 0;
}

总结

​ 理解能力还是不足,运用不够灵活,差点学死了....

标签:取模,Johnny,int,res,ll,个数,Grandmaster,MOD
来源: https://www.cnblogs.com/dialectics/p/13052739.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有