[POI2017]Podzielno
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 364 Solved: 160
[Submit][Status][Discuss]
Description
B进制数,每个数字i(i=0,1,...,B-1)有a[i]个。你要用这些数字组成一个最大的B进制数X(不能有前导零,不需要
用完所有数字),使得X是B-1的倍数。q次询问,每次询问X在B进制下的第k位数字是什么(最低位是第0位)。
Input
第一行包含两个正整数B(2<=B<=10^6),q(1<=q<=10^5)。
第二行包含B个正整数a[0],a[1],a[2],...,a[B-1](1<=a[i]<=10^6)。
接下来q行,每行一个整数k(0<=k<=10^18),表示一个询问。
Output
输出q行,每行一个整数,依次回答每个询问,如果那一位不存在,请输出-1。
Sample Input
3 3
1 1 1
0
1
2
1 1 1
0
1
2
Sample Output
0
2
-1
2
-1
HINT
题解:
一个B进制数+B-1后各位数字之和模B-1意义下不变
证明:+B相当于在次低位+1,-1相当于在最低位-1,
如果某一位加一,如果进位,则下一位会加一,这一位会减去B-1,所以对各位数字之和模B-1意义下的影响是+1
如果某一位减一,如果退位,则下一位会减一,这一位会加上B-1,所以对各位数字之和模B-1意义下的影响是-1
所以原数+B-1后各位数字之和在模B-1意义下不变
那么显然一个B进制数是B-1的倍数的充要条件是各位数字之和模B-1等于0
题里要求让这个数尽量大
那么我们就先把所有数都选上,并且大的数放到高位,然后删去尽量少的数
因为a[i]>=1,所以直接删除即可。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define ll long long 8 #define N 1000007 9 using namespace std; 10 inline ll read() 11 { 12 ll x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 18 int n,m; 19 ll a[N]; 20 21 int main() 22 { 23 n=read(),m=read(); 24 ll x=0; 25 for (int i=0;i<n;i++) 26 a[i]=read(),(x+=a[i]*i)%=(n-1); 27 if (x) a[x]--; 28 for (int i=1;i<n;i++) a[i]+=a[i-1]; 29 while(m--) 30 { 31 x=read()+1; 32 int ans=-1,l=0,r=n-1; 33 while(l<=r) 34 { 35 int mid=(l+r)>>1; 36 if (a[mid]>=x) ans=mid,r=mid-1; 37 else l=mid+1; 38 } 39 printf("%d ",ans); 40 } 41 }