杂题
今天帮同学做了几道笔试题,下面这道题做了一个半小时。
题意:有$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; }