天天看点

Google APAC 2017 Round E

下午有时间于是又做了下Round E, 算法太弱导致只做了前三道,记录下。

  • A. Diwali lightnings
  • B. Beautiful Numbers
  • C. Partioning Number

A. Diwali lightnings

送分题,循环序列统计B出现了多少次,注意边界条件即可,略过

B. Beautiful Numbers

题目就不贴了,可以去codejam上去看,给定一个数N,求一个进制K,使N在K进制下可以表示为连续的1。

暴力法可以通过小数据,但最大10^19次方显然无法通过。设K进制表示下有m个1,m最大为64(2进制),最小为2(N-1进制)。

N = K^(m-1)+K^(m-2)+…+K+1

当m确定时,N是K的单调递增函数,因此可以用二分法解决,最终时间复杂度是64*O(logN),编程时注意枚举m时,上界是n,可能有溢出的问题,注意。贴下代码,但似乎有些BUG会溢出,欢迎讨论:

#include <iostream>

using namespace std ;
typedef unsigned long long ull ;
ull m, n ;
int T ;

ull work(){
    for(m= ;m>= ;m--) {
        ull lk = ;
        ull hk = n-;
        while (lk<=hk) {
            ull mk = lk/+hk/ ;
            if(lk%== && hk%==)
                mk++ ;
            ull res =  ;
            ull tmp =  ;
            bool legal = true ;
            for(int j= ;j<m ;j++){
                ull tr = res+tmp ;
                if(tr<res || tr<tmp){
                    //!溢出
                    legal = false ;
                    break ;
                }
                res = tr ;
                ull ttmp = tmp*mk ;
                if(ttmp<tmp || ttmp<mk){
                    legal= false ;
                    break ;
                }
                tmp = ttmp ;
            }
            if(!legal || res>n){
                hk = mk- ;
                continue ;
            }
            if(res==n){
                return mk ;
            }
            if(res<n){
                lk = mk+ ;
                continue ;
            }
        }
    }

}

int main() {
    cin >> T ;
    for(int i= ;i<T ;i++) {
        cin >> n ;
        cout << "Case #" << i+ << ": " ;
        ull res = work() ;
        cout << res << endl ;
    }
}
           

C. Partioning Number

题意比较长,不再赘述,要求将N个球放到多个桶里面即把数N分割为多个正整数,形成一个序列,要求:

  • 第一个数被D整除
  • 所有的数字相差小于等于2,即只能有三个不同的数字
  • non-decreasing

根据分析我们可以知道第一个数字x只能是D的整倍数,同时后面只能由x+1和x+2,我们设三种不同的数字的个数分别为a,b,c,有多少种满足条件的a,b,c就是结果。

有: a*x+b*(x+1)+c*(x+2) = N

a > 0, b >=0, c>=0

我们可以枚举a,b再加上枚举x共三层循环。大数据会超时

考虑如何降低,我们整理方程:

(a+b+c)*x+b+2c = N

令 p = a+b+c, q = b+2c , 此外 q = N-p*x

由于a>0 则有约束: b+c< p, b+2c=q

这就是一个线性规划问题,求b+2c=q这条直线上有多少个整数点满足b+c< p。很简单的线性规划,注意一些边界条件,例如c是否整数,边界上的点是否满足,b>0, c>0等。假设交点是(b0,c0)几个分界点,b0=0, b0=p等

AC代码

#include <iostream>
using namespace std ;
int T, N, D ;

int work(){
    int ans =  ;
    for(int x=D ;x<=N ;x+=D){
        int ma = N/x ;
        for(int p= ;p<=ma ;p++) {
            int q = N-p*x ;
            int mb = *p-q ;
            if(mb<= )
                continue ;
            if(mb>p) {
                if(q>=) {
                    ans += (q + ) / ;
                    if (q %  == )
                        ans++;
                }
            }
            else {
                ans += mb / ;
                if (q %  ==  && mb%==)
                    ans--;
            }
        }
    }
    return ans ;
}

int main() {
    cin >> T ;
    for (int t= ;t<=T ;t++){
        cin >> N >> D ;
        cout << "Case #" << t << ": " ;
        int res = work() ;
        cout << res << endl ;
    }

}
           

继续阅读