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 }
View Code

 

posted @ 2018-05-24 19:35  Blue233333  阅读(155)  评论(0编辑  收藏  举报