洛谷P5226 [SCOI2015]小凸解密码 题解

题目传送门

题目描述

小凸得到了一个密码盘,密码盘被等分成 nn 个扇形,每个扇形上有一个数字 (0 \sim 9)(0∼9),和一个符号 (( + 或 * ))。密码盘解密的方法如下:

首先,选择一个位置开始,顺时针地将数字和符号分别记在数组 AA 和数组 CC 中。解密的方法如下:

B_0 = A_0B
0
​ =A
0

当 x > 0x>0 时:
若 C_xC
x
​ 为 +,B_x = (A_x + A_{x - 1}) % 10B
x
​ =(A
x
​ +A
x−1
​ )%10
若 C_xC
x
​ 为 *,B_x = (A_x \times A_{x - 1}) % 10B
x
​ =(A
x
​ ×A
x−1
​ )%10
操作完成后,可以得到一个长度为 nn 的数组 BB,然后以 B_0B
0
​ 为起点将 BB 数组顺时针写成一个环,解密就完成了,称得到的环为答案环。

现在小凸得到了一份指令表,指令表上有 2 种操作。一种指令是修改操作,即改变原来密码盘上一个位置的数字和符号。另一种指令是询问操作,具体如下:

首先从指令给出的位置开始完成解密,得到答案环。
答案环上会有一些 00 连在一起,将这些连在一起的 00 称为零区间,找出其中距离 B_0B
0
​ 最远的那个零区间,输出这个距离(零区间和 B_0B
0
​ 的距离定义为:零区间内所有 00 到 B_0B
0
​ 距离中的最小值)。

分析

本题较为烧脑,请脑细胞不够的同学直接学习代码。

  1. 解密的方法如下:

B_0 = A_0B
0
​ =A
0

当 x > 0x>0 时:
若 C_xC
x
​ 为 +,B_x = (A_x + A_{x - 1}) % 10B
x
​ =(A
x
​ +A
x−1
​ )%10
若 C_xC
x
​ 为 *,B_x = (A_x \times A_{x - 1}) % 10B
x
​ =(A
x
​ ×A
x−1
​ )%10
操作完成后,可以得到一个长度为 nn 的数组 BB,然后以 B_0B
0
​ 为起点将 BB 数组顺时针写成一个环,解密就完成了,称得到的环为答案环。

  1. 数据范围:

对于 20 %20% 数据,5 \leq n \leq 10^5, 5 \leq m \leq 10005≤n≤10
5
,5≤m≤1000;
对于 60 %60% 数据,5 \leq n \leq 10^5, 5 \leq m \leq 10^45≤n≤10
5
,5≤m≤10
4

对于 100 %100% 数据,5 \leq n, m \leq 10^55≤n,m≤10
5

AC代码

#include<bits/stdc++.h>
using namespace std; 

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=100005;
int n,m,a[N],b[N],c[N],cnt;
struct node
{
    int l,r;
    node(int _l=0,int _r=0):l(_l),r(_r){};
    inline friend bool operator < (const node &a,const node &b)
    {return a.l<b.l;}
};
set<node>S;
#define It set<node>::iterator
inline int nxt(int i){return i==n?1:i+1;}
inline int bef(int i){return i==1?n:i-1;}
inline It Nxt(It it){return it==--(--S.end())||it==--S.end()?++S.begin():++it;}
inline It Bef(It it){return it==++S.begin()||it==S.begin()?--(--S.end()):--it;}
It it;

void Insert(int p)
{
    node t=node(p,p),suf,pre;
    it=S.lower_bound(t),suf=*it;
    if(suf.l!=n+1&&suf.l==p+1)S.erase(it),t.r=suf.r;
    it=--S.lower_bound(t),pre=*it;
    if(pre.r&&pre.r==p-1)S.erase(it),t.l=pre.l;
    S.insert(t);
}
void Delete(int p)
{
    node t=node(p,p),cur;
    it=--S.upper_bound(t),cur=*it,S.erase(it);
    if(cur.l<p)S.insert(node(cur.l,p-1));
    if(cur.r>p)S.insert(node(p+1,cur.r));
} 
void modify(int p,int x,int y)
{
    if(x&&!y)Insert(p);
    if(!x&&y)Delete(p);
}
bool in(int l,int r,int p)
{
    if(l<=r)return l<=p&&p<=r;
    else return l<=p||p<=r;
}
int calc(int l,int r,int p)
{
    if(in(l,r,p))return 0;
    return min(min(abs(p-l),abs(p-r)),min(n-abs(p-r),n-abs(p-l)));
}
int solve(node tmp,int p)
{
    if(tmp.l==1)
    {
        node t=*--(--S.end());
        if(t.r==n)tmp.l=t.l;
    }
    if(tmp.r==n)
    {
        node t=*++S.begin();
        if(t.l==1)tmp.r=t.r;
    }
    return calc(tmp.l,tmp.r,p);
}
int query(int p)
{
    if(S.size()==2)return -1;
    int pos=p+n/2;if(pos>n)pos-=n;
    node t=node(pos,pos),suf,pre;
    it=S.lower_bound(t);
    int res=0;
    it=Bef(Bef(Bef(it))); 
    for(int i=1;i<=6;i++)
        res=max(res,solve(*it,p)),it=Nxt(it);
    return res;
}
int main()
{
    //freopen("lx.in","r",stdin);
    //freopen("lx.out","w",stdout);
    n=getint(),m=getint();
    for(int i=1;i<=n;i++)a[i]=getint(),c[i]=(getchar()=='+'?0:1);
    for(int i=1;i<=n;i++)b[i]=(c[i]?a[bef(i)]*a[i]%10:(a[bef(i)]+a[i])%10);
    S.insert(node(0,0)),S.insert(node(n+1,n+1));
    for(int i=1;i<=n;i++)if(!b[i])Insert(i);
    while(m--)
    {
        int op=getint(),p=getint()+1,x=0,y=0;
        if(op==1)
        {
            a[p]=getint(),c[p]=(getchar()=='+'?0:1);
            x=b[p],y=b[p]=(c[p]?a[bef(p)]*a[p]%10:(a[bef(p)]+a[p])%10);
            modify(p,x,y);
            x=b[nxt(p)],y=b[nxt(p)]=(c[nxt(p)]?a[p]*a[nxt(p)]%10:(a[p]+a[nxt(p)])%10);
            modify(nxt(p),x,y);
        }
        else 
        {
            modify(p,b[p],a[p]);
            printf("%d\n",query(p));
            modify(p,a[p],b[p]); 
        }
    }
    return 0;
}

函数还是较难看懂的,主程序更难看懂,因为题目等级是NOI等级(NOIP是省赛),我还想给它IOI or root等级(最高等级NOI+/CTSC)。

猜你喜欢

转载自blog.csdn.net/yingyouyu/article/details/87901712
今日推荐