牛客挑战赛36

正题

      放假苟在电脑室打比赛懒得回家。

      T1:环

      因为保证是奇数,所以可以想出一个类似于增添补出或者漏一个的方法。

      可以很容易的求出这个序列的id序列,和全部值的和。

      处理出偶数位的前缀和和后缀和。对于一个偶数位,它的值就是pre[i]+las[i]-tot,对于一个奇数位,它的值就是tot-pre[i-1]-las[i+1];

      T2:字符串

      坑了我挺久的,要看懂题,对于m<n的情况,出现循环节当且仅当3*(n-m)=n,2*m=n或者n-m|gcd(n,m)

      为什么我就不具体说了,自己可以画出来看看。

      对于m>=n的情况,当且仅当 n|m,才成立。

      T3:纸飞机

       我就说好像做过这种题,首先要先去做做导弹拦截,知道一个性质,最少分割下降子序列个数与最长不下降子序列长度相等。

       具体证明可以自行找规律。

       那么这题就变成了删去其中一个数找最长不下降子序列的问题。

      考虑什么样的点是“必需的”,也就是将它删去,最长不下降子序列长度一定减少,也就是出现了断层。

      为了方便,我们从后往前做,把一个点所在的最长不上升子序列长度找出来,那么我们就可以很快的知道一个点是否存在于一条最长不下降子序列中。

      对于同一层的点,也就是f值相等的点,我们看看是否存在多个点都满足存在于LIS中这个条件。如果存在,那么这些点都不是必须点,否则如果只有一个点,那么这个点就是必需点,其他同层点都不是。

      输出的时候不是必需点的就输出mmax,否则输出mmax-1。

      T4:排名估算

       这题有点东西,学到了,单独讲,可以看学习笔记

      T7:Nim游戏

      第一次接触分治FWT,比赛时一直在寻找异或卷积的规律,还是见识少。

      首先可以把题目转化为(1+b_ix^{a_i})的异或卷积的第0项的系数,然后我们对它进行分治异或卷积就可以了。

      对于ai相同的,可以先把它们暴力O(1)卷积起来,假设现在对一个次数区间内的多项式进行卷积,必定是左边一部分与右边一部分乘起来。

      然而,一个区间内的集合幂级数的次数不一定在这个区间范围之内,但是很容易可以看出只会分布在两个区间内。

     假设这个区间是[x,x+2^k),那么这个区间的集合幂级数的次数只会分布在[0,2^k)\bigcup [x,x+2^k)之间,那么我们用sa表示前面一部分的系数,sb表示后面一部分的次数,卷积的时候发现两边的sb乘起来实际上会贡献到新的sa,而且发现恰好左边是[x,x+2^{k-1})右边是[x+2^{k-1},x+2^k),所以右边的第k位为1,讨论一下就可以得出当前区间的集合幂级数了。

#include<bits/stdc++.h>
using namespace std;

const int N=131072;
int n;
const long long mod=998244353;
long long a[N],b[N];
long long sa[N],sb[N];
long long ta[N],tb[N],tc[N],td[N];
long long inv=499122177;
long long A[N],B[N],X[N];

void read(int&x){
	x=0;
	char ch=getchar();
	while(ch<'0' || ch>'9') ch=getchar();
	while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}

void fwt(long long*a,int L){
	long long X,Y;
	for(int l=2;l<=L;l<<=1)
		for(int i=0;i<L;i+=l)
			for(int x=i,y=i+l/2;y<i+l;x++,y++){
				X=a[x]+a[y],Y=a[x]-a[y];
				X>=mod?X-=mod:0;Y<0?Y+=mod:0;
				a[x]=X,a[y]=Y;
			}
}

void ifwt(long long*a,int L){
	long long X,Y;
	for(int l=L;l>=2;l>>=1)
		for(int i=0;i<L;i+=l)
			for(int x=i,y=i+l/2;y<i+l;x++,y++){
				X=a[x]+a[y];Y=a[x]-a[y];
				X>=mod?X-=mod:0;Y<0?Y+=mod:0;
				X&1?X+=mod:0,Y&1?Y+=mod:0;
				a[x]=X/2,a[y]=Y/2;
			}
}

void solve(int x,int l){
	if(l==0){
		sa[x]=a[x];sb[x]=b[x];
		return ;
	}
	int y=x+l;
	solve(x,l/2);solve(y,l/2);
	for(int i=0;i<l;i++) ta[i]=sa[x+i],tb[i]=sb[x+i],tc[i]=sa[y+i],td[i]=sb[y+i];
	fwt(ta,l);fwt(tb,l);fwt(tc,l);fwt(td,l);
	for(int i=0;i<l;i++) X[i]=ta[i]*tc[i]%mod;ifwt(X,l);
	for(int i=0;i<l;i++) sa[x+i]=X[i];
	for(int i=0;i<l;i++) X[i]=ta[i]*td[i]%mod;ifwt(X,l);
	for(int i=0;i<l;i++) sb[y+i]=X[i];
	for(int i=0;i<l;i++) X[i]=tb[i]*tc[i]%mod;ifwt(X,l);
	for(int i=0;i<l;i++) sb[x+i]=X[i];
	for(int i=0;i<l;i++) X[i]=tb[i]*td[i]%mod;ifwt(X,l);
	for(int i=0;i<l;i++) sa[y+i]=X[i];
}

int main(){
	read(n);
	int x,y;
	long long t1,t2;
	for(int i=0;i<N;i++) a[i]=1;
	for(int i=1;i<=n;i++){
		read(x);read(y);
		t1=(a[x]+b[x]*y)%mod;
		t2=(b[x]+a[x]*y)%mod;
		a[x]=t1;b[x]=t2;
	}
	solve(0,N/2);
	printf("%lld",(sa[0]+sb[0]+mod-1)%mod);
} 

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/104031622