Description

小凸得到了一个密码盘,密码盘被等分成 \(N\) 个扇形,每个扇形上有一个数字(0~9),和一个符号(“+”或"*")

密码盘解密的方法如下:

首先,选择一个位置开始,顺时针地将数字和符号分别记在数组 \(A\) 和数组 \(C\) 内

解密的方法如下

\(B0=A0\)

当 \(x>0\) 时:

若 \(Cx\) 为“+”,\(Bx=(Ax+Ax-1) \%10\) ,注意:\(x-1\) 是下标值

若 \(Cx\) 为“*”,\(Bx= (Ax×Ax-1) \%10\) ,注意:\(x-1\) 是下标值

操作完成后,可以得到一个长度为 \(n\) 的数组 \(B\) ,然后以 \(B0\) 为起点将 \(B\) 数组顺时针写成一个环,解密就完成了,称得到的环为答案环。

现在小凸得到了一份指令表,指令表上有2种操作。

一种指令是修改操作,即改变原来密码盘上一个位置的数字和符号。

另一种指令是询问操作,具体如下:

首先从指令给出的位置开始完成解密,得到答案环。

答案环上会有一些 \(0\) 连在一起,将这些连在一起的 \(0\) 称为零区间,找出其中距离 \(B0\) 最远的那个零区间,输出这个距离。

零区问和 \(B0\) 的距离定义为:零区问内所有 \(0\) 到 \(B0\) 距离中的最小值。

Input

第 1 行包含2个整数 \(n\) , \(m\) ,代表密码盘大小和指令个数

接下来 \(n\) 行,每行包含1个整数和1个字符,按顺时针顺序给出了密码盘上的数组和符号

接下来 \(m\) 行,依次给出指令

每行第1个整数代表指令类型

若第1个整数为1,代表本行对应指令为修改操作,之后依次有2个整数 \(pos\) ,\(num\) 和1个字符 \(opt\) ,分别代表修改的位置,以及修改后该位置的数字和字符

若第1个整数为2,代表本行对应指令位询问操作,之后有1个整数 \(pos\) ,代表本次操作中解密的开始位置

密码盘上的位置标号为 \(0\) 到 \(n-1\)

数据保证合法,即数据中 \(0 \leq pos < N\),\(0 \leq num \leq 9\),\(opt\) 为“+”或“*”

Output

对于每个询问操作1行,输出答案,若答案环上没有0,输出-1

Sample Input

5 8

0 *

0 *

0 *

0 *

0 *

2 0

1 0 1 +

1 2 1 +

2 3

1 1 1 +

1 3 1 +

1 4 1 +

2 4

Sample Output

0

2

-1

HINT

第1个询问,答案环为[0,0,0,0,0],仅有1个零区间,且 \(B0\) 在其中,所以距离是0

对于第2个询问,答案环为[0,0,1,0,l],有2个零区间,(0,1)和 \(B0\) 距离是o,(3,3)和 \(B0\) 距离是2,故答案为2

对于第3个询问,答案环为[1,2,2,2,2],没有零区间,答案是-1

对于 \(100 \%\) 数据,\(5 \leq n,m \leq 10^5\)


想法

修改看起来可以很快,那先搞查询。

拆环为链,线段树维护 \(B\) 数组

要求距离最远的0区间,我感觉距离又最大又最小很麻烦,就二分吧

二分 \(mid\) 后对应了环上的一段区间 \([pos+mid,pos+n-mid]\),分情况讨论:

1.区间内包含完整的0区间:那个完整的0区间到 \(B0\) 的距离肯定比 \(mid\) 大,所以 \(l=mid+1\)

2.区间内不含完整的0区间,但区间内有0(即0在区间边缘):那么最终答案肯定不会比 \(mid\) 大,所以 \(r=mid\)

3.区间内没有0:答案肯定小于 \(mid\) ,所以 \(r=mid-1\)

线段树维护区间有没有完整的0区间及左右端点连续的0的个数,随便搞一搞(可不行……细节不少……)

剩下的随便 \(yy\) 一下,总复杂度 \(O(nlog^2n)\) 简单粗暴。

网上有用 \(set\) 维护0区间端点的 \(O(nlogn)\) 做法,不过我还是觉得线段树友好【逃】


代码

必须承认,细节很多。。。

但是 \(1A\) 了可喜可贺!

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch) && ch!='-') ch=getchar();
if(ch=='-') f=-1,ch=getchar();
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
} const int N = 200005; int n,m;
int a[N],c[N],b[N]; int root,cnt,ch[N*2][2];
struct fea{ int full,lm,rm; }d[N*2];
fea merge(fea ls,int lenl,fea rs,int lenr){
fea x;
x.full=max(ls.full,rs.full);
if(ls.rm+rs.lm>0 && ls.rm!=lenl && rs.lm!=lenr) x.full=1;
x.lm= (ls.lm==lenl ? ls.lm+rs.lm : ls.lm);
x.rm= (rs.rm==lenr ? rs.rm+ls.rm : rs.rm);
return x;
}
void build(int x,int l,int r){
if(l==r){
if(b[l]==0) d[x]=(fea){0,1,1};
else d[x]=(fea){0,0,0};
return;
}
int mid=(l+r)>>1;
build(ch[x][0]=++cnt,l,mid);
build(ch[x][1]=++cnt,mid+1,r);
d[x]=merge(d[ch[x][0]],mid-l+1,d[ch[x][1]],r-mid);
}
void change(int x,int l,int r,int pos,int num){
if(l==r){
if(num==0) d[x]=(fea){0,1,1};
else d[x]=(fea){0,0,0};
return;
}
int mid=(l+r)>>1;
if(pos<=mid) change(ch[x][0],l,mid,pos,num);
else change(ch[x][1],mid+1,r,pos,num);
d[x]=merge(d[ch[x][0]],mid-l+1,d[ch[x][1]],r-mid);
}
fea ask(int x,int l,int r,int L,int R){
if(l==L && r==R) return d[x];
int mid=(l+r)>>1;
if(R<=mid) return ask(ch[x][0],l,mid,L,R);
else if(L>mid) return ask(ch[x][1],mid+1,r,L,R);
return merge(ask(ch[x][0],l,mid,L,mid),mid-L+1,ask(ch[x][1],mid+1,r,mid+1,R),R-mid);
} int main()
{
char chh[2];
n=read(); m=read();
for(int i=1;i<=n;i++){
a[i]=read();
scanf("%s",chh);
if(chh[0]=='+') c[i]=1;
else c[i]=2;
} a[0]=a[n];
for(int i=1;i<=n;i++){
if(c[i]==1) b[i]=(a[i]+a[i-1])%10;
else b[i]=(a[i]*a[i-1])%10;
b[i+n]=b[i];
}
build(root=++cnt,1,n*2); int pos,opt;
while(m--){
opt=read();
if(opt==1){
pos=read()+1; a[pos]=read();
scanf("%s",chh);
c[pos]= (chh[0]=='+' ? 1 : 2 );
if(c[pos]==1) b[pos]=(a[pos]+a[pos-1])%10;
else b[pos]=(a[pos]*a[pos-1])%10;
b[pos+n]=b[pos];
change(root,1,n*2,pos,b[pos]);
change(root,1,n*2,pos+n,b[pos+n]); if(pos==n) { a[0]=a[pos]; pos=1; }
else pos++;
if(c[pos]==1) b[pos]=(a[pos]+a[pos-1])%10;
else b[pos]=(a[pos]*a[pos-1])%10;
b[pos+n]=b[pos];
change(root,1,n*2,pos,b[pos]);
change(root,1,n*2,pos+n,b[pos+n]);
}
else{
pos=read()+1;
change(root,1,n*2,pos,a[pos]); change(root,1,n*2,pos+n,a[pos]);
int l=0,r=n/2,mid;
while(l<r){
mid=(l+r)>>1;
fea x=ask(root,1,n*2,pos+mid,pos+n-mid);
if(x.full) l=mid+1;
else if(x.lm || x.rm) r=mid;
else r=mid-1;
}
if(l==0){
fea x=ask(root,1,n*2,pos,pos+n);
if(!x.full && !x.lm && !x.rm) printf("-1\n");
else printf("0\n");
}
else printf("%d\n",l);
change(root,1,n*2,pos,b[pos]); change(root,1,n*2,pos+n,b[pos]);
}
} return 0;
}


[bzoj4447] [loj#2010] [Scoi2015] 小凸解密码的更多相关文章

  1. bzoj4447[Scoi2015]小凸解密码

    4447: [Scoi2015]小凸解密码 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 150  Solved: 58[Submit][Status ...

  2. bzoj4447 SCOI2015 小凸解密码 password

    传送门:bzoj4447 题解: 调试简直恶心,不过调完发现其实还是挺好写的. 用\(\mathrm{set}\)维护一段\(0\)区间的左右端点,每次最多修改两个点,所以很好维护. 查询的时候在\( ...

  3. 2019.03.26 bzoj4447: [Scoi2015]小凸解密码(线段树)

    传送门 题意简述:咕咕咕 思路:考虑预处理出bbb数组,然后每次改动aaa都只会对第iii和i+1i+1i+1这两个位置产生影响,于是可以用线段树来维护bbb数组. 现在求答案的方法是断环为链,倍增整 ...

  4. 「SCOI2015」小凸解密码 解题报告

    「SCOI2015」小凸解密码 题意:给一个环,定义一段连续的极长\(0\)串为\(0\)区间,定义一个位置的离一个\(0\)区间的距离为这个位置离这个区间中\(0\)的距离的最小值,每次询问一个位置 ...

  5. bzoj 4447 小凸解密码

    bzoj 4447 小凸解密码 先将原始状态的 \(B\) 处理出来,可以发现,若不修改,则每次指定的起始位置不同,对这个环 \(B\) 带来的影响只有 \(B_0\) 不同,即每次 \(B_0=A_ ...

  6. [bzoj4446] [loj#2009] [Scoi2015] 小凸玩密室

    Description 小凸和小方相约玩密室逃脱,这个密室是一棵有 \(n\) 个节点的完全二叉树,每个节点有一个灯泡.点亮所有灯泡即可逃出密室.每个灯泡有个权值 \(Ai\) ,每条边也有个权值 \ ...

  7. 【LOJ】#2010. 「SCOI2015」小凸解密码

    题解 断环为链,把链复制两份 用set维护一下全是0的区间,然后查找x + n / 2附近的区间,附近各一个过不去,最后弃疗了改为查附近的两个,然后过掉了= = 熟练掌握stl的应用,你值得拥有(雾 ...

  8. BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配

    BZOJ_4443_[Scoi2015]小凸玩矩阵_二分+二分图匹配 Description 小凸和小方是好朋友,小方给小凸一个N*M(N<=M)的矩阵A,要求小秃从其中选出N个数,其中任意两个 ...

  9. 【BZOJ4445】[Scoi2015]小凸想跑步 半平面交

    [BZOJ4445][Scoi2015]小凸想跑步 Description 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸n边形,N个顶点按照逆时针从0-n-l编号.现 ...

随机推荐

  1. vue 插件大全

    UI组件 element - 饿了么出品的Vue2的web UI工具套件 Vux - 基于Vue和WeUI的组件库 mint-ui - Vue 2的移动UI元素 iview - 基于 Vuejs 的开 ...

  2. JavaScript实现版本号比较

    /* * JavaScript实现版本号比较 * 传入两个字符串,当前版本号:curV:比较版本号:reqV * 调用方法举例:Version('5.12.3','5.12.2'),将返回true * ...

  3. CITRIX VPX安装

    Step 1:下载.ova格式的VPX,如下图: Step 2:初始化VPX,如下图: 本例设置NSIP为192.168.188.150/24 Step 3:打开浏览器http://192.168.1 ...

  4. ASP.NET MVC API与JS进行POST请求时传递参数 -CHPowerljp原创

    在API前添加    [HttpPost] 表示只允许POST方式请求 [HttpPost] public IHttpActionResult Get_BIGDATA([FromBody]Datas  ...

  5. Batch Normalization批量归一化

    BN的深度理解:https://www.cnblogs.com/guoyaohua/p/8724433.html BN: BN的意义:在激活函数之前将输入归一化到高斯分布,控制到激活函数的敏感区域,避 ...

  6. 前端——BOM与DOM

    目录 前戏 window对象 window的子对象 navigator对象(了解即可) screen对象(了解即可) history对象(了解即可) location对象 弹出框 计时相关 DOM H ...

  7. 【退役记】CSP2019 退役记

    Day -1 机房自习,因为一些奇怪原因心不在焉 我可能太在意csp了 晚上有点扛不住去七楼阳台思考人生,得到了一些惊人的结论想下来由于某种原因继续跑到七楼思考人生 然后晚自习下课仰天大笑出门去,我辈 ...

  8. 洛谷P3413 SAC#1 - 萌数 题解 数位DP

    题目链接:https://www.luogu.com.cn/problem/P3413 题目大意: 定义萌数指:满足"存在长度至少为2的回文子串"的数. 求区间 \([L,R]\) ...

  9. 1094 谷歌的招聘 (20 分)C语言

    2004 年 7 月,谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌(如下图)用于招聘.内容超级简单,就是一个以 .com 结尾的网址,而前面的网址是一个 10 位素数,这个素数是自然常数 e ...

  10. Spring Boot 添加Druid连接池(1.5 版本)

    Druid是一个关系型数据库连接池,是阿里巴巴的一个开源项目,地址:https://github.com/alibaba/druid .Druid不但提供连接池的功能,还提供监控功能,可以实时查看数据 ...