10.29T1 倍增+同余
6037 -- 【PA2015】Hazard
Description
有n个人在轮流玩赌博机,一开始编号为i的人有a[i]元钱。赌博机可以抽象为一个长度为m的仅包含1和-1的序列,若抽到1,那么你将得到1块钱;若抽到-1,你将输掉1块钱。
第1局,第1个人会抽到序列中的第1项;第2局,第2个人会抽到序列中的第2项;第3局,第3个人会抽到序列中的第3项......即:第i个人抽完后轮到第i+1个人去抽,特别地,第n个人抽完后轮到第1个人去抽。序列第i项被抽到之后,下一个被抽到的将会是第i+1项,特别地,序列第m项被抽到之后,下一个被抽到的将会是第1项。
如果在某一轮,有个人输光了所有的钱,那么这场赌博游戏就会结束,请求出游戏在哪一轮结束,或者判断这个游戏会永远进行下去。
第1局,第1个人会抽到序列中的第1项;第2局,第2个人会抽到序列中的第2项;第3局,第3个人会抽到序列中的第3项......即:第i个人抽完后轮到第i+1个人去抽,特别地,第n个人抽完后轮到第1个人去抽。序列第i项被抽到之后,下一个被抽到的将会是第i+1项,特别地,序列第m项被抽到之后,下一个被抽到的将会是第1项。
如果在某一轮,有个人输光了所有的钱,那么这场赌博游戏就会结束,请求出游戏在哪一轮结束,或者判断这个游戏会永远进行下去。
Input
第一行包含一个正整数n(1<=n<=1000000),表示玩家的个数。
第二行包含n个正整数a[1],a[2],...,a[n](1<=a[i]<=1000000),依次表示每个玩家一开始持有的钱数。
第一行包含一个正整数m(1<=m<=1000000),表示序列的长度。
第四行包含一个长度为m的仅包含W和P的字符串,表示这个序列,其中W表示1,P表示-1。
第二行包含n个正整数a[1],a[2],...,a[n](1<=a[i]<=1000000),依次表示每个玩家一开始持有的钱数。
第一行包含一个正整数m(1<=m<=1000000),表示序列的长度。
第四行包含一个长度为m的仅包含W和P的字符串,表示这个序列,其中W表示1,P表示-1。
Output
若游戏会永远进行下去,输出-1。否则输出游戏在哪一轮结束。
Sample Input
4
2 3 2 1
3
WPP
Sample Output
12
Source
root
此题难度很大
容易发现每个人都是独立的,那么我们只需要求出每个人在什么时候会没钱,最早没钱的那个人就是使得大家离开的那个人。如果大家都不会没钱那么就不会离开。
对于每个人,用类似 st 表的方式计算出每个人在经过2i轮之后硬币的变化,就可以轻松的算出这个人离开的时间。
时间复杂度 O(NlogN)
实际上要维护三个倍增数组代表最大的支付前缀,到的位置,还有支付和
code:
1 #include<iostream> 2 #include<cstdio> 3 #define N 1000005 4 using namespace std; 5 long long n; 6 long long m; 7 long long NXT[N][21],PAY[N][21],DEL[N][21]; 8 void initalize() { 9 for(long long i=1; i<=20; i++) { 10 for(long long j=0; j<n; j++) { 11 NXT[j][i]=NXT[NXT[j][i-1]][i-1]; 12 DEL[j][i]=DEL[j][i-1]+DEL[NXT[j][i-1]][i-1]; 13 PAY[j][i]=max(PAY[j][i-1],DEL[j][i-1]+PAY[NXT[j][i-1]][i-1]); 14 } 15 } 16 } 17 bool complete_round(long long step,long long &now,long long &money) { 18 for(long long i=20; i>=0; i--) { 19 if(step&(1<<i)) { 20 if(money>PAY[now][i]) { 21 money-=DEL[now][i]; 22 now=NXT[now][i]; 23 } else return false; 24 } 25 } 26 return true; 27 } 28 long long rest_walk(long long now,long long money) { 29 long long footstep=0; 30 for(long long i=20; i>=0; i--) { 31 if(money>PAY[now][i]) { 32 footstep+=(1<<i)*n; 33 money-=DEL[now][i]; 34 now=NXT[now][i]; 35 } 36 } 37 return footstep; 38 } 39 long long a[N],ans[N],isinf[N],min0=99999999999999999,bcc,siz[N],win[N],belong[N]; 40 long long read(){ 41 long long x=0,f=1; 42 char c=getchar(); 43 while(!isdigit(c)){ 44 if(c=='-')f=-1; 45 c=getchar(); 46 } 47 while(isdigit(c)){ 48 x=(x<<3)+(x<<1)+c-'0'; 49 c=getchar(); 50 } 51 return x*f; 52 } 53 int main() { 54 // freopen("game7.in","r",stdin); 55 n=read(); 56 for(long long i=0; i<n; i++) { 57 a[i]=read(); 58 } 59 m=read(); 60 for(long long i=0; i<m; i++) { 61 char c=getchar(); 62 while(c!='W'&&c!='P')c=getchar(); 63 if(c=='W')win[i]=-1; 64 else win[i]=1; 65 } 66 for(long long i=0; i<m; i++) { 67 if(belong[i])continue; 68 long long now=i; 69 bcc++; 70 while(1) { 71 siz[bcc]++; 72 belong[now]=bcc; 73 NXT[now][0]=(now+n)%m; 74 PAY[now][0]=win[now]; 75 DEL[now][0]=win[now]; 76 now=NXT[now][0]; 77 if(belong[now])break; 78 } 79 } 80 initalize(); 81 for(long long i=0; i<n; i++) { 82 long long money=a[i],now=i%m; 83 ans[i]=(i+1); 84 if(complete_round(siz[belong[now]],now,money)) { 85 long long delta=a[i]-money; 86 if(delta<=0) { 87 isinf[i]=1; 88 continue; 89 } 90 ans[i]+=(a[i]/delta)*siz[belong[now]]*n-n; 91 a[i]%=delta; 92 ans[i]+=rest_walk(NXT[i%m][0],a[i]); 93 } 94 else ans[i]+=rest_walk(i%m,a[i]); 95 } 96 long long flag=0; 97 for(long long i=0; i<n; i++) { 98 if(!isinf[i]) { 99 min0=min(min0,ans[i]); 100 flag=1; 101 } 102 } 103 if(flag)cout<<min0; 104 else puts("-1"); 105 return 0; 106 }
over