【BZOJ4295】[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项。
如果在某一轮,有个人输光了所有的钱,那么这场赌博游戏就会结束,请求出游戏在哪一轮结束,或者判断这个游戏会永远进行下去。

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。

Output

若游戏会永远进行下去,输出-1。否则输出游戏在哪一轮结束。

Sample Input

4
2 3 2 1
3
WPP

Sample Output

12

题解:显然我们应该找到循环节,然后将一个循环内的所有人放到一起考虑。假如我们已经拿出了某个循环中的所有人,我们先对于每个人,处理处他在转一圈时,收益的最小值(亏损的最大值);再处理出整个循环的权值和。那么如果权值和是负数,那么这个人肯定是先转若干圈,直到他的剩余钱数不足这个亏损的最大值,然后找到他第一个把钱输光的位置即可。如果权值和是正数,我们看这个人的钱数是否大于这个亏损的最大值。如果大于,则这个人永远不会输光,否则找到他第一个把钱输光的位置。

以上内容都可以通过前缀和,前缀最大值,前缀pre,后缀和,后缀最大值,后缀nxt搞定。特别地,如果n>m或m>n都要特殊考虑一下。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=1000010;
typedef long long ll;
int n,m;
ll ans;
int A[maxn],B[maxn],C[maxn],v[maxn],vis[maxn],s[maxn],s1[maxn],s2[maxn],m1[maxn],m2[maxn],p[maxn];
int memp[maxn<<1],*last=memp+maxn,mn[maxn];
char str[maxn];
inline int abs(int x) {return x>0?x:-x;}
void work(int S)
{
int i,j,L=0,sum=0;
for(i=S;!vis[i];i=(i+n)%m,L++) p[L]=i,v[L]=(str[i]=='W')?1:-1,sum+=v[L],vis[i]=1;
s2[L]=m2[L]=0;
for(i=0;i<L;i++) s1[i]=s1[i-1]+v[i],m1[i]=min(m1[i-1],s1[i]);
for(i=L-1;i>=0;i--) s2[i]=s2[i+1]+v[i],m2[i]=max(m2[i+1],s2[i]),mn[i]=min(s2[i]+m1[i-1],s2[i]-m2[i+1]);
if(sum<0)
{
sum=-sum;
for(i=0;i<L;i++)
{
j=p[i];
if(A[j]!=-1&&A[j]+mn[i]>0) B[j]=(A[j]+mn[i]+sum-1)/sum,A[j]-=B[j]*sum;
}
}
for(i=0;i<=L;i++) last[i]=last[-i]=-2;
for(i=0;i<L;i++)
{
j=p[i];
if(last[s1[i-1]]==-2) last[s1[i-1]]=i-1;
if(A[j]!=-1&&A[j]+mn[i]<=0&&last[-s2[i]-A[j]]!=-2)
ans=min(ans,(last[-s2[i]-A[j]]+L-i+(ll)B[j]*L)*n+C[j]);
}
for(i=0;i<=L;i++) last[i]=last[-i]=-2;
for(i=L-1;i>=0;i--)
{
j=p[i],last[s2[i+1]]=i+1;
if(A[j]!=-1&&A[j]+mn[i]<=0&&last[s2[i]+A[j]]!=-2)
ans=min(ans,(last[s2[i]+A[j]]-i-1+(ll)B[j]*L)*n+C[j]);
}
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
//freopen("bz4295.in","r",stdin);
n=rd();
int i;
for(i=0;i<n;i++) A[i]=rd();
m=rd();
scanf("%s",str);
for(i=0;i<m;i++) C[i]=i+1;
for(i=m;i<n;i++) if(A[i]<A[i%m]) A[i%m]=A[i],C[i%m]=i+1;
for(i=n;i<m;i++) A[i]=-1;
ans=1ll<<60;
for(i=0;i<m;i++) if(!vis[i]) work(i);
if(ans==(1ll<<60)) printf("-1");
else printf("%lld",ans);
return 0;
}

【BZOJ4295】[PA2015]Hazard 乱搞的更多相关文章

  1. BZOJ4295 : [PA2015]Hazard

    第i轮,a[i%n]+=b[i%m]. 枚举i,计算它变为0的次数,假设为t,那么有t=i+kn. 对于所有的i和k,(i+kn)%m形成了若干个总长度为m的环. 对于每个a[i],先在环中求出一轮最 ...

  2. URAL 1827 Indigenous Wars(排序、乱搞)

    题意:给一个长度为n数组{a[i]}.有m个操作Ti,Si,Li表示找以Ti值结束,以Si值开始,长度为Li的连续子串.找到后,将区间的答案值设为1.一开始答案值全部为0.最后输出n个答案值. 好久没 ...

  3. UVA 11853 [dfs乱搞]

    /* 大连热身E题 不要低头,不要放弃,不要气馁,不要慌张 题意: 在1000×1000的格子内有很多个炮弹中心,半径给定. 为某人能否从西部边界出发,从东部边界走出. 不能输出不能,能的话输出最北边 ...

  4. Codeforces 732e [贪心][stl乱搞]

    /* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给n个插座,m个电脑.每个插座都有一个电压,每个电脑都有需求电压. 每个插座可以接若干变压器,每个变压器可以使得电压变为x/2上取整. 有无限个变 ...

  5. 【BZOJ-4692】Beautiful Spacing 二分答案 + 乱搞(DP?)

    4692: Beautiful Spacing Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 46  Solved: 21[Submit][Statu ...

  6. 【BZOJ-3578】GTY的人类基因组计划2 set + map + Hash 乱搞

    3578: GTY的人类基因组计划2 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 367  Solved: 159[Submit][Status][ ...

  7. 【BZOJ-2937】建造酿酒厂 前缀和 + 展环为链 + 乱搞

    2937: [Poi2000]建造酿酒厂 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 70  Solved: 24[Submit][Status][D ...

  8. SCOI 2013 密码 & 乱搞

    题意: Fish 是一条生活在海里的鱼.有一天他很无聊,就到处去寻宝.他找到了位于海底深处的宫殿,但是一扇带有密码锁的大门却阻止了他的前进.通过翻阅古籍,Fish 得知了这个密码的相关信息:1. 该密 ...

  9. 种树 & 乱搞

    题意: 在一个(n+1)*(m+1)的网格点上种k棵树,树必须成一条直线,相邻两棵树距离不少于D,求方案数. SOL: 这题吧...巨坑无比,本来我的思路是枚举每一个从(0,0)到(i,j)的矩形,然 ...

随机推荐

  1. XML文件标签名一致,而属性值不同,如何遍历取值写法 摘录

    <EssentialFunctions>      <Qualification description="We Offer" source="AdDe ...

  2. 查看Linux是32位还是64位的方法

    发布:JB01   来源:脚本学堂     [大 中 小] 本文介绍下,快速查看linux系统是32位还是64位的方法,有需要的朋友参考下吧. 本节内容:查看linux操作系统的位数 一,方法A:un ...

  3. 使用 nice、cpulimit 和 cgroups 限制 cpu 占用率

    Linux内核是一名了不起的马戏表演者,它在进程和系统资源间小心地玩着杂耍,并保持系统的能够正常运转. 同时,内核也很公正:它将资源公平地分配给各个进程. 但是,如果你需要给一个重要进程提高优先级时, ...

  4. Redhat7 Mesos安装

    $ sudo yum install -y tar wget git 1. 手工安装mavenwget http://mirrors.cnnic.cn/apache/maven/maven-3/3.3 ...

  5. PKI/CA

    PKI( Public Key Infrastructure )指的是公钥基础设施. CA ( Certificate Authority )指的是认证中心. PKI从技术上解决了网络通信安全的种种障 ...

  6. eclipse配置 嵌入式-基于linux

    Eclipse可以安装在各种操作系统.这里是安装到Ubuntu 10.10上.有两种方法实现安装,一是采用Ubuntu的软件源:二是从官方下载后解压. 1.  通过Ubuntu软件源安装 $ sudo ...

  7. Python删除列表中元素

    Python中列表(list)是很常用的数据结构,删除列表中的元素有几种方法 列表的remove方法 lst = [1, 1, 3, 4] lst.remove(1) # lst->[1, 3, ...

  8. 今天遇到个PHP不知原因的报内部错误

    今天遇到个PHP不知原因的报内部错误 纠结了很久想尽了办法,1.apache日志 2.错误级别 ,还差点就把自己写的那个破烂不堪的日志系统加上去了 纠结了很久还是无果,在最终,最终发现了 原来是类命名 ...

  9. Java反射机制的基本概念与使用

    本篇文章分为以下几个部分: 1.认识反射 2.反射的源头(Class类) 3.利用反射操作构造方法 4.利用反射调用类中的方法 5.反射中的invoke方法 6.利用反射调用类中的属性 反射在我们普通 ...

  10. C#连接手机安装软件和发送信息

    今天突然想到怎么用winform程序连接自己的安卓手机,然后做发送短信的操作,查了很多资料 发现用ADB.exe 这个安卓自带的调试库 可以实现挺多功能的 前提是你自己手机已经和你电脑连接成功过,就是 ...