BZOJ4724: [POI2017]Podzielno
$n \leq 1e6$,$n$进制下的$0,1,...,n-1$每个数有$a_i$个,$1 \leq a_i \leq 1e6$。$q \leq 1e5$个询问,每次问用这些数字拼成的$n-1$的倍数的最大的那个数(不一定全选),它的某一位是多少。
这个数字用传统十进制表示就是$\sum_{i=0}^{k-1}a_in^i$,$k$表示那个$n-1$倍数最大数的位数。可以看出在$mod \ \ n-1$下$n^i$是没用的。因此只要数位和为$n-1$的倍数即可。
可以先把所有数选起来,然后挑掉一些凑成$n-1$的倍数。
然后我在思考怎么挑,顿时想到这是国外的题,我这种长年CF选手应担负起实现中华民族……(以下省略若干)一定要把他搞出来。
然后一查题解(真香),回去看了数字范围,$1 \leq a_i$。。。。。。我是傻子。直接拿走一个数即可。
然后前缀和+二分。
1 #include<stdio.h> 2 #include<string.h> 3 //#include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 #define LL long long 8 int qread() 9 { 10 char c; int s=0,t=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (t=-1); 11 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*t; 12 } 13 14 // 15 16 int n,m; 17 #define maxn 1000011 18 int a[maxn]; LL pre[maxn]; 19 20 int main() 21 { 22 n=qread(); m=qread(); 23 int tot=0; 24 for (int i=0;i<n;i++) a[i]=qread(),tot+=1ll*i*a[i]%(n-1),tot-=tot>=n-1?n-1:0; 25 if (tot) a[tot]--; 26 pre[0]=a[0]; for (int i=1;i<n;i++) pre[i]=pre[i-1]+a[i]; pre[n]=-1; 27 28 LL q; 29 while (m--) 30 { 31 scanf("%lld",&q); 32 if (q>=pre[n-1]) puts("-1"); 33 else printf("%d\n",lower_bound(pre,pre+n,q+1)-pre); 34 } 35 return 0; 36 }