CTSC2017T1密钥

写一篇博客来记录自己有多么sb。

大家都说这是一道普及-的题,一年前我做不起,我可以说我太弱啦,我就普及组水平,今年我还是做不起……

看大佬题解都是:开个桶就好啦!

我:你在说什么……

首先把环拉成链,倍长。

如果确定$i$这个位置是起始位置,那么特征值就是$\sum\limits_{j=1}^{n-1} (p_j!=0 , sum(A_{i+1}...A_{i+j})>0) $。

那么我们先记录一个前缀和,后面所提到的$A$都是前缀和。$\sum\limits_{j=1}^{n-1} (p_j!=0 , A_{i+j} > A_{i})$。

我们可以这样来考虑,我们把$A$看作高度,从左到右连起来看成折线,我每次在$A_{i}$高度处拉根线,比线高的,并且向上走的(就是p!=0),的折线的个数就是特征值

因为$A_i-A_{i-1}$要么是1要么是-1,所以我们每次减掉或者加上某一个取值的个数就可以了,所以这就是开个桶的意义。

然后如果$p!=0$是B的位置的时候,如果图不变,相当于比线低的,往下走的,的折线的个数,就是特征值,

然后因为折线起始点和终止点的高度都是拉的这根线的高度,

所以比线低的,往下走的,和比线低或者相等的,往上走的,是可以一一对应的,数目是相等的,

比线低或者相等的,往上走的个数,就是k-比线高的,并且向上走的个数

我在说啥……

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
#define db double
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i>=(b);--i)
const int maxn=4e7+7;
int n,k,seed,now,S,p[maxn],cnt[maxn],A[maxn],ans1,ans2,ans3;

char cc; ll ff;
template<typename T>void read(T& aa) {
	aa=0;cc=getchar();ff=1;
	while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
	if(cc=='-') ff=-1,cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	aa*=ff;
}

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;
    memset(p, 0, sizeof(p));
    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++;
    }
}

int main() {
	generateData();
	For(i,1,n) p[i+n]=p[i];
	A[0]=n+1; For(i,1,n<<1) A[i]=A[i-1]+(p[i]? 1:-1);
	For(i,1,n) if(p[i]) ++cnt[A[i]],now+=A[i]>A[0];
	For(i,1,n) {
		if(p[i]) {
			now-=cnt[A[i]];//from A[i]-1 to A[i]
			--cnt[A[i]];
			++cnt[A[i+n]];
			now+=A[i+n]>A[i];
		}
		else {
			now+=cnt[A[i]+1];//from A[i]+1 to A[i]
			if(now==0) ans1=i;
			if(now==S) ans2=i;
			if(now==k-S) ans3=i;
		}
	}
	printf("%d\n%d\n%d\n",ans1,ans2,ans3);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Serene-shixinyi/p/8977653.html