1 条题解

  • 0
    @ 2025-8-24 21:52:31

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar asuldb
    哭晕了喵

    搬运于2025-08-24 21:52:31,当前版本为作者最后更新于2019-08-22 21:12:51,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目

    一个显然的暴力就是枚举X\rm X的位置,把A\rm A视为11B\rm B视为1-1,从这个位置开始求一遍前缀和,特征值即为所有前缀和大于00AA

    我们对第一个空位置做一遍这个暴力,考虑一下X\rm X移动会对其他位置的前缀和产生什么样的影响

    如果移动到的位置原来是一个B\rm B,相当于把这个1-1放到了最后处理,于是前缀和数组整体+1+1

    移动到的位置是一个AA,那么除了这个AA以外的前缀和少了最初的一个+1+1,整体1-1,而AA位置的前缀和再处理下一个位置的时候就变成了prenprei+prei1pre_n-pre_i+pre_i-1,又因为pren=0pre_n=0,所以变成了1-1

    于是我们维护一个桶,开一个指针表示当前00的位置,整体+1,1+1,-1可以直接移动指针,特殊修改直接结合当前指针的值在桶里修改即可

    这样第一二问就做完了,第三问显然可以在用上述的方法模拟一遍,但是有这样一个结论,一个kk11kk1-1组成序列,kk11中前缀和大于00的个数加上kk1-1中前缀和小于00的个数等于kk

    证明非常简单,当一个前缀和从00变大再变成00的过程中,111-1的个数显然是相等的,等于这次前缀和“回归0”过程中的数的个数一半,其中所有11的前缀和必然是大于00的;前缀和从00变小再变成00同理,所以这个结论是正确的

    于是对于第三问,我们只需要判断一下当前前缀和大于00(在第三问中对应了所有BB的前缀和小于00的个数)是否等于kSk-S即可

    代码

    #include<bits/stdc++.h>
    #define re register
    #define LL long long
    const int maxn=2e7+5;
    int p[maxn],pre[maxn],tax[maxn],np[maxn],id[maxn];
    int seed,n,k,S,tot,now,ans1,ans2,beg,ans3;
    inline int getrand() {
    	seed=((seed*12321)^9999)%32768;
    	return seed;
    }
    void generateData() {
    	scanf("%d%d%d",&k,&seed,&S);
    	int t=0;n=k*2+1;
    	for( int i = 1; i <= n; ++i ) 
    		p[i]=(getrand()/128)%2,t+=p[i];
    	int i=1;
    	while(t>k) {
    		while(p[i]==0) ++i;
    		p[i]=0;--t;
    	}
    	while(t<k) {
    		while(p[i]==1) ++i;
    		p[i]=1;++t;
    	}
    }
    inline void calc(int pos) {
    	if(tot==0) ans1=id[pos];
    	if(tot==S) ans2=id[pos];
    	if(tot==k-S) ans3=id[pos];
    	if(ans1&&ans2&&ans3) {
    		printf("%d\n%d\n%d\n",ans1,ans2,ans3);
    		exit(0);
    	}
    }
    int main() {
    	generateData();
    	for(re int i=1;i<=n;i++) if(!p[i]) {beg=i;break;}
    	for(re int i=1;i<=n;i++) {
    		id[i]=beg;np[i]=p[beg++];if(beg>n) beg=1;
    	}
    	for(re int i=2;i<=n;i++) pre[i]=(pre[i-1])+(np[i]?1:-1);
    	for(re int i=2;i<=n;i++) if(np[i]) tax[pre[i]+k]++;
    	for(re int i=k+1;i<=k+k;++i) tot+=tax[i];
    	calc(1);now=k;
    	for(re int i=2;i<=n;i++) 
    		if(np[i]) ++now,tot-=tax[now],
    			tax[pre[i]+k]--,tax[pre[i]+k-1]++;
    		else tot+=tax[now],--now,calc(i);
    	return 0;
    }
    
    • 1

    信息

    ID
    2736
    时间
    1000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者