Processing math: 3%

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——如果在左边,取knk+1n,表示这个0是前导0;如果在右边,取1k1k-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\n",1,n-1,2,n);
        else
        {
            if(pos<=n/2)printf("%d %d %d %d\n",pos,n,pos+1,n);
            else printf("%d %d %d %d\n",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 1b[n]=s \pm 1(此处s是整个序列的和),而s是一个奇数,所以它们不能同号。

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

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

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

同样,我们把和不为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\n%d ",L),L++;
            int x,y;
            if((x=getb(L,R,L))==0){printf("%d\n",L); continue;}
            if((y=getb(L,R,R))==0){printf("%d\n",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\n",mid); break;}
                if((val>0&&f==1)||(val<0&&f==-1))l=mid+1;
                else r=mid-1;
            }
        }
    }
    return 0;
}
View Code
复制代码

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

posted @   Zinn  阅读(46)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 从 Windows Forms 到微服务的经验教训
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
点击右上角即可分享
微信分享提示