题目描述
B
B
B进制数,每个数字
i
(
i
=
0
,
1
,
.
.
.
,
B
−
1
)
i(i=0,1,...,B-1)
i(i=0,1,...,B−1)有
a
[
i
]
a[i]
a[i] 个。你要用这些数字组成一个最大的
B
B
B 进制数
X
X
X (不能有前导零,不需要用完所有数字),使得
X
X
X 是
B
−
1
B-1
B−1 的倍数。
q
q
q 次询问,每次询问
X
X
X 在
B
B
B 进制下的第
k
k
k 位数字是什么(最低位是第
0
0
0 位)。
输入格式
第一行包含两个正整数
B
(
2
≤
B
≤
1
0
6
)
,
q
(
1
≤
q
≤
1
0
5
)
B(2\le B \le 10^6),q(1 \le q \le 10^5)
B(2≤B≤106),q(1≤q≤105)。
第二行包含
B
B
B 个正整数
a
[
0
]
,
a
[
1
]
,
a
[
2
]
,
.
.
.
,
a
[
B
−
1
]
,
0
<
a
[
i
]
≤
1
0
6
a[0],a[1],a[2],...,a[B-1],0 < a[i] \le 10^6
a[0],a[1],a[2],...,a[B−1],0<a[i]≤106。
接下来
q
q
q 行,每行一个整数
k
(
0
≤
k
≤
1
0
18
)
k(0 \le k \le 10^{18} )
k(0≤k≤1018),表示一个询问。
输出格式
输出q行,每行一个整数,依次回答每个询问,如果那一位不存在,请输出-1。
样例输入
3 3
1 1 1
0
1
2
样例输出
0
2
-1
数据范围与提示
输入格式中已给出
题解
需要明确一个性质:
a ∗ B i m o d ( B − 1 ) = a a*B^{i}mod(B-1)=a a∗Bimod(B−1)=a
既然如此,题目就变成了选取一些数字,让它们之和对 B − 1 B-1 B−1取模等于 0 0 0。注意,题目已经告诉我们 a [ i ] > 0 a[i]>0 a[i]>0,说明每个数字都至少有一个,那么直接去掉那个取模结果即可。剩下数字的排列自然是从大到小。
代码:
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
typedef long long ll;
using namespace std;
ll B,q,sum,a[1000005],wss,k,lst[1000005],lstr[1000005],tot;
map <ll,ll> exc;
int main(){
scanf("%lld%lld",&B,&q);
const ll mod=B-1;
for(int i=0;i<=B-1;i++){
scanf("%lld",&a[i]);
sum+=(i*a[i])%mod;
sum%=mod;
}
if(sum!=0){
a[sum]-=1;
}
for(int i=0;i<=B-1;i++){
if(a[i]==0) continue;
exc[wss]=i;
lst[++tot]=wss;
wss+=a[i];
}
lst[++tot]=wss;
exc[wss]=-1;
for(int i=tot;i>=0;i--){
lstr[i]=lst[tot-i];
}
for(int i=1;i<=q;i++){
scanf("%lld",&k);
ll aaa=*lower_bound(lstr,lstr+tot,k,greater<ll> () );
printf("%d\n",exc[aaa]);
}
return 0;
}