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

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

  • 相关阅读:
    Windows Azure Web Site (19) Azure Web App链接到VSTS
    Windows Azure Virtual Machine (35) Azure VM通过Linked DB,执行SQL Job
    Azure PowerShell (16) 并行开关机Azure ARM VM
    Windows Azure Virtual Network (12) 虚拟网络之间点对点连接VNet Peering
    Azure ARM (21) Azure订阅的两种管理模式
    Windows Azure Platform Introduction (14) 申请海外的Windows Azure账户
    Azure ARM (20) 将非托管磁盘虚拟机(Unmanage Disk),迁移成托管磁盘虚拟机(Manage Disk)
    Azure ARM (19) 将传统的ASM VM迁移到ARM VM (2)
    Azure ARM (18) 将传统的ASM VM迁移到ARM VM (1)
    Azure Automation (6) 执行Azure SQL Job
  • 原文地址:https://www.cnblogs.com/Zinn/p/15194466.html
Copyright © 2011-2022 走看看