题意
有nnn个球要放到mmm个箱子里,有以下两条规则:
1、若把标号为iii的球放进了第jjj个盒子,那么标号为2∗i2*i2∗i的球一定要在第j+1j+1j+1个盒子里面(((若j<m)j<m)j<m)
2、若把标号为iii的球放进了第jjj个盒子,并且k∗2=ik*2=ik∗2=i,那么标号为kkk的球一定要在第j−1j-1j−1个盒子里面(((若j>1)j>1)j>1)
求第一个箱子里最多可以放多少球。
思路
因为222,所以第一个箱子里只能放奇数编号的球。
如果第一个箱子里放aaa,那么a∗2m−1≤na*2^{m-1}\leq na∗2m−1≤n
那么我们就知道2m2^m2m里可以放了,然后有
a∗2x(x≡0(mod m),a≡1(mod 2),a∗2x+m−1<=n)a∗2^x(x≡0(mod\ m),a≡1(mod\ 2),a∗2^{x+m−1}<=n)a∗2x(x≡0(mod m),a≡1(mod 2),a∗2x+m−1<=n)
所以我们每次让n/2m−1n/2^{m-1}n/2m−1,统计一遍奇数,然后每次让n/2mn/2^mn/2m,统计奇数。
因为nnn比较大,所以我们需要用高精度。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
const long long P = 1e11;
const int MAXN = 1000;
int t, m, l, al;
long long a[MAXN + 1], ans[MAXN + 1];
char s[10001];
void init() {
memset(s, 0, sizeof(s));
memset(ans, 0, sizeof(ans));
scanf("%s", s + 1);
scanf("%d", &m);
l = strlen(s + 1);
int g = 0;
long long k = 1;
for (int i = l; i >= 1; i--) {
a[g] += (s[i] - 48) * k;
k *= 10;
if (k == P) k = 1, g++;
}
l = MAXN;
al = 0;
}
void div(long long d) {
long long g = 0;
for (int i = l; i >= 0; i--) {
a[i] += g * P;
g = a[i] % d;
a[i] /= d;
}
while (!a[l] && l)
l--;
}
void countAns() {
long long g = 0;
ans[0] += a[0] % 2;
for (int i = l; i >= 0; i--) {
ans[i] += (a[i] + g * P) / 2;
g = a[i] % 2;
}
int t = std::max(l - 1, al);
if (ans[t + 1]) t++;
for (int i = 0; i <= t; i++)
if (ans[i] >= P) {
ans[i] -= P;
ans[i + 1]++;
}
if (ans[t + 1]) al = t + 1;
else al = t;
}
void print() {
printf("%lld", ans[al]);
while (al--) {
if (ans[al] < 1e10) printf("0");
if (ans[al] < 1e9) printf("0");
if (ans[al] < 1e8) printf("0");
if (ans[al] < 1e7) printf("0");
if (ans[al] < 1e6) printf("0");
if (ans[al] < 1e5) printf("0");
if (ans[al] < 1e4) printf("0");
if (ans[al] < 1e3) printf("0");
if (ans[al] < 1e2) printf("0");
printf("%lld", ans[al]);
}
printf("\n");
}
int main() {
scanf("%d", &t);
for (; t; t--) {
init();
div(1 << m - 1);
countAns();
while (a[0]) {
div(1 << m);
countAns();
}
print();
}
}