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。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
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)。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
(这场比赛题目大多是关注简单情况、单个位置、特殊(端)点;很机智的思路。)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 本地部署 DeepSeek:小白也能轻松搞定!
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 从 Windows Forms 到微服务的经验教训
· 李飞飞的50美金比肩DeepSeek把CEO忽悠瘸了,倒霉的却是程序员
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee