zoukankan      html  css  js  c++  java
  • cf 1562(div2)

    比赛连接:Dashboard - Codeforces Round #741 (Div. 2) - Codeforces

    做了A和B,B还WA了一次。被C卡住。大掉分。

    C

    分析:

    二进制和倍数放一起不好考虑,那只考虑0,1,2倍就好了。

    1倍前面可以增加任意个0。

    2倍就是二进制左移一位。左移完右边多了个0。

    综上,如果字符串里没有0,随便取长度相同的;如果有0,取一个0找到它的位置(k)——如果在左边,取(k)到(n)和(k+1)到(n),表示这个0是前导0;如果在右边,取(1)到(k)和(1)到(k-1),表示这个0是左移完增加的0。

    代码如下:

    #include<iostream>
    using namespace std;
    int const N=2e4+5;
    int T,n;
    char st[N];
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%s",&n,st+1); int pos=-1;
            for(int i=1;i<=n;i++)
                if(st[i]=='0'){pos=i; break;}
            if(pos==-1)printf("%d %d %d %d
    ",1,n-1,2,n);
            else
            {
                if(pos<=n/2)printf("%d %d %d %d
    ",pos,n,pos+1,n);
                else printf("%d %d %d %d
    ",1,pos,1,pos-1);
            }
        }
        return 0;
    }
    View Code

    D

    分析:

    首先,序列的每个值在计算时不是1就是-1。所以要想和为0,序列长度必须是偶数。也就是说,当询问的序列长度是奇数时,就至少要去掉一个数;当长度是偶数时,如果整个序列和不为0,那么至少要去掉两个数,可以随便去掉一个端点,然后按奇数长度考虑。

    下面我们考虑一个奇数长度序列的情况:

    设(b[i])表示去掉(i)后序列的和。可以想到去掉一个数以后,它后面的序列和要乘一个-1(因为奇偶性变了)。

    根据这个,再结合每个位置计算时不是1就是-1,想想可以发现(b[i])和(b[i+1])的差值要么是0,要么是2。

    关注两个端点(b[1])和(b[n]):

    如果(b[1])和(b[n])中有0,那么对应的那个端点就是答案;

    如果二者都不是0,那么肯定是一正一负。因为(b[1]=-s pm 1),(b[n]=s pm 1)(此处(s)是整个序列的和),而(s)是一个奇数,所以它们不能同号。

    又因为所有(b[i])都是偶数(去掉(i)位置后序列长度为偶数),差值是0或2,所以中间必定有一个值为0的(b[i])。

    到这里就可以做D1了:对于一个询问,如果已经和为0,输出0;否则如果长度是奇数,输出1,否则输出2。

    进一步考虑D2:需要找到删除的位置,也就是找到(b[i]=0)的(i)。

    同样,我们把和不为0的偶数长度序列直接去掉一个端点,变成奇数长度序列处理。

    对于一个奇数长度序列,如果答案不在端点,那么答案在序列中的某个(b[i]=0)的位置;(b)都是偶数,差值为0或2,说白了就是连续变化;而端点的(b)异号。

    所以我们可以二分找到(b[i]=0)的位置(i)。时间复杂度(O(qlogn))。

    代码如下:

    #include<iostream>
    using namespace std;
    int const N=3e5+5;
    int T,n,q,s[N];
    char st[N];
    int getb(int L,int R,int p)
    {
        int f=(L&1)?1:-1, ret=f*(s[p-1]-s[L-1]);
        f=-f; ret+=f*(s[R]-s[p]);
        return ret;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%s",&n,&q,st+1);
            for(int i=1,x,f=1;i<=n;i++,f=-f)
            {
                x=(st[i]=='+')?1:-1;
                s[i]=s[i-1]+f*x;
            }
            for(int i=1,L,R,f;i<=q;i++)
            {
                scanf("%d%d",&L,&R);
                if(s[R]-s[L-1]==0){puts("0"); continue;}
                if((R-L+1)&1)puts("1");
                else printf("2
    %d ",L),L++;
                int x,y;
                if((x=getb(L,R,L))==0){printf("%d
    ",L); continue;}
                if((y=getb(L,R,R))==0){printf("%d
    ",R); continue;}
                if(x>0)f=1; else f=-1; int l=L,r=R;
                while(l<=r)
                {
                    int mid=((l+r)>>1),val=getb(L,R,mid);
                    if(val==0){printf("%d
    ",mid); break;}
                    if((val>0&&f==1)||(val<0&&f==-1))l=mid+1;
                    else r=mid-1;
                }
            }
        }
        return 0;
    }
    View Code

    (这场比赛题目大多是关注简单情况、单个位置、特殊(端)点;很机智的思路。)

  • 相关阅读:
    推荐一波好的代码托管
    二十一、如何导入svg图片
    二十、滑动开关css
    十九、CSS如何引入字体
    十八、移动端rem布局
    十五、css3 Filter--滤镜
    十四、css动画基础知识
    十三、初始化标签默认样式
    十二、移动端头部声明
    十一、使用a标签打电话、发短信、发邮件
  • 原文地址:https://www.cnblogs.com/Zinn/p/15194466.html
Copyright © 2011-2022 走看看