杂题

今天帮同学做了几道笔试题,下面这道题做了一个半小时。

题意:有$q$个询问,每次询问在$[l,r]$区间内,$k$进制表示中,$k-1$的数量最多的数是哪个数。

比如当$k=2$时,9的二进制是1001,有两个1.

$1<=q<=100000,2<=k<=16,1<=l<=r<=10^{16}$

 

题解:我的做法是,把$l$和$r$拆成$k$进制,然后记录两个数组从高位到低位最后一个相等的位置,然后从后往前枚举,不够借位即可。

 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
int pre[70], suf[70];
int ans[70];
/*
思路:首先l,r都转换成k进制,然后先扫到第一个不相等的数,
*/
int main()
{
    //freopen("1.txt", "r", stdin);
    int q; scanf("%d", &q);
    while(q--)
    {
        int k;
        ll l, r;
        scanf("%d %lld %lld", &k, &l, &r);
        memset(ans, 0, sizeof(ans));
        memset(pre, 0, sizeof(pre));
        memset(suf, 0, sizeof(suf));
        int ind1 = 0, ind2 = 0;
        while(l)
        {
            pre[ind1++] = l % k;
            l = l / k;
        }
        while(r)
        {
            suf[ind2++] = r % k;
            r = r / k;
        }
       int flag = 100;
       for(int i = max(ind1, ind2) - 1; i >= 0; i--)
       {
           if(pre[i] == suf[i])
           {
               flag = i;
           }
           else break;
       }
       int t = max(ind1, ind2);
       for(int i = 0; i < t; i++)
       {
           if(i < flag - 1 && i != t - 1)
           {
               if((suf[i] != (k - 1))) suf[i + 1]--; ///这一步最关键
               ans[i] = k - 1;
           }
           else
           {
               if(suf[i] == k - 1)
               {
                   ans[i] = k - 1;
               }
               else  ans[i] = max(0, min(pre[i], suf[i]));
           }
       }
       ll ans1 = 0;
       while(ans[t] == 0) t--;
       for(int i = t; i >= 0; i--)
       {
        //   printf("%d ", ans[i]);
           ans1 = ans1 * k;
           ans1 += ans[i];
       }
      // printf("\n");
       printf("%lld\n", ans1);
    }
    return 0;
}
Code

 

posted @ 2018-09-17 22:27  汪汪鱼  阅读(178)  评论(0编辑  收藏  举报