1. 程式人生 > >BZOJ4724: [POI2017]Podzielno

BZOJ4724: [POI2017]Podzielno

AC int #define lse lower div sum clu fine

$n \leq 1e6$,$n$進制下的$0,1,...,n-1$每個數有$a_i$個,$1 \leq a_i \lq 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

BZOJ4724: [POI2017]Podzielno