Darkmoon Faire

题目:

Darkmoon Faire

题意:

n个数,分成若干段,使得每段最大值在奇数位上,最小值在偶数位上。

问分割方案数。

题解:

每段max,min让人想到区间异或和异或区间最大值异或区间最小值这题。

利用分治,来完成方程转移。

跨越中线的情况分4种:

1.max,min都在左边

2.max,min都在右边

3.max在左,min在右

4.max在右,min在左

具体实现需要用到大量前缀和和差分来优化,实现较复杂。

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define last Lst
#define gc getchar
#define int long long
const int N=1e6+5;
const int mod=998244353;
int n,m,a[N],S1[N],S2[N],S3[N],S4[N],ma[N],mi[N],A[N],f[N],ji[N],ou[N];
//char buf[1<<21],*p1=buf,*p2=buf;
//inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
void solve(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)/2;
	solve(l,mid);
	S1[l-1]=S2[l-1]=0;
	if((l-1)%2==1)S1[l-1]=f[l-1];
	else S2[l-1]=f[l-1];
	for(int i=l;i<=mid;i++)
	{
		S1[i]=S1[i-1];
		S2[i]=S2[i-1];
		if(i%2==1)S1[i]=(S1[i]+f[i])%mod;
		else S2[i]=(S2[i]+f[i])%mod;
	}
	for(int i=l;i<=r;i++)A[i]=ji[i]=ou[i]=0;
    int maxl,maxr,minl,minr,pin1,pin2;
    maxl=minl=mid;
    for(int i=mid;i>=l;i--)
    {
    	if(a[i]>a[maxl])maxl=i;
    	if(a[i]<a[minl])minl=i;
        ma[i]=maxl;
        mi[i]=minl;
    }
    maxr=minr=mid+1;
    for(int i=mid+1;i<=r;i++)
    {
    	if(a[i]>a[maxr])maxr=i;
    	if(a[i]<a[minr])minr=i;
        ma[i]=maxr;
        mi[i]=minr;
    }

	S3[l-1]=S4[l-1]=0;
	if((l-1)%2==1&&mi[l]%2==1)S3[l-1]=f[l-1];
	if((l-1)%2==0&&mi[l]%2==0)S4[l-1]=f[l-1];
	for(int i=l;i<mid;i++)
	{
		S3[i]=S3[i-1];
		S4[i]=S4[i-1];
		if(i%2==1&&mi[i+1]%2==1)S3[i]=(S3[i]+f[i])%mod;
		if(i%2==0&&mi[i+1]%2==0)S4[i]=(S4[i]+f[i])%mod;
	}
    //1.max left min left

    pin1=mid+1;
    for(int i=mid;i>=l;i--)
    {
        while(pin1<=r&&a[mi[pin1]]>a[mi[i]]&&a[ma[pin1]]<a[ma[i]])pin1++;
        //mid+1~pin1-1
        if((ma[i]-i+1)%2==1&&(mi[i]-i+1)%2==0)
        {
	        A[mid+1]=(A[mid+1]+f[i-1])%mod;
	        A[pin1]=(A[pin1]-f[i-1]+mod)%mod;
	    }
    }
    //2.max right min right

    pin1=mid;
    for(int i=mid+1;i<=r;i++)
    {
        while(pin1>=l&&a[mi[pin1]]>a[mi[i]]&&a[ma[pin1]]<a[ma[i]])pin1--;
        //pin1+1~mid
        if(ma[i]%2==mi[i]%2)continue;
        if(ma[i]%2==0)
		{
			if(pin1==l-1)f[i]=(f[i]+S1[mid-1])%mod;
			else f[i]=(f[i]+S1[mid-1]-S1[pin1-1]+mod)%mod;
		}
        else{
        	if(pin1==l-1)f[i]=(f[i]+S2[mid-1])%mod;
			else f[i]=(f[i]+S2[mid-1]-S2[pin1-1]+mod)%mod;
		}
//        for(int j=pin1;j<=mid-1;j++)
//	        if(ma[i]%2!=j%2)
//	        {
//	        	if(ma[i]%2==0)f[i]=(f[i]+S1[j]-S1[j-1]+mod)%mod;
//	        	else f[i]=(f[i]+S2[j]-S2[j-1]+mod)%mod;
//	        }
    }
    //3.max left min right

    pin1=pin2=mid+1;
    for(int i=mid;i>=l;i--)
    {
        while(pin1<=r&&a[mi[i]]<a[mi[pin1]])pin1++;
        while(pin2<=r&&a[ma[i]]>a[ma[pin2]])pin2++;
        if(pin1<pin2)
        {
            //pin1~pin2-1
            if((ma[i]-i+1)%2==0)continue;
            if(i%2==0)
			{
				ji[pin1]=(ji[pin1]+f[i-1])%mod;
				ji[pin2]=(ji[pin2]-f[i-1]+mod)%mod;
			}
			else{
				ou[pin1]=(ou[pin1]+f[i-1])%mod;
				ou[pin2]=(ou[pin2]-f[i-1]+mod)%mod;			
			}
//            for(int j=pin1;j<=pin2-1;j++)
//	            if(mi[j]%2!=i%2)
//			        f[j]=(f[j]+f[i-1])%mod;
        }
    }
    //4.max right min left

    pin1=pin2=mid;
    for(int i=mid+1;i<=r;i++)
    {
        while(pin1>=l&&a[mi[i]]<a[mi[pin1]])pin1--;
        while(pin2>=l&&a[ma[i]]>a[ma[pin2]])pin2--;
        if(pin1>pin2)
        {
			//pin2+1~pin1
			if(ma[i]%2==0)//mi[j+1]%2==1 j%2==1
			{
				if(pin2==l-1)f[i]=(f[i]+S3[pin1-1])%mod;
				else f[i]=(f[i]+S3[pin1-1]-S3[pin2-1]+mod)%mod;
			}
			else{//mi[j+1]%2==0 j%2==1
				if(pin2==l-1)f[i]=(f[i]+S4[pin1-1])%mod;
				else f[i]=(f[i]+S4[pin1-1]-S4[pin2-1]+mod)%mod;			
			}
//			for(int j=pin2;j<=pin1-1;j++)
//				if((ma[i]-j)%2==1&&(mi[j+1]-j)%2==0)
//					f[i]=(f[i]+f[j])%mod;
        }
    }
    for(int i=l+1;i<=r;i++)A[i]=(A[i]+A[i-1])%mod;
    for(int i=mid+1;i<=r;i++)f[i]=(f[i]+A[i])%mod;
    for(int i=l+1;i<=r;i++)ji[i]=(ji[i]+ji[i-1])%mod;
    for(int i=mid+1;i<=r;i++)
		if(mi[i]%2==1)f[i]=(f[i]+ji[i])%mod;
    for(int i=l+1;i<=r;i++)ou[i]=(ou[i]+ou[i-1])%mod;
    for(int i=mid+1;i<=r;i++)
		if(mi[i]%2==0)f[i]=(f[i]+ou[i])%mod;
	solve(mid+1,r);
}
signed main()
{
	int T=read();
	while(T--)
	{
		n=read();
		for(int i=1;i<=n;i++)f[i]=0;
		for(int i=1;i<=n;i++)a[i]=read();
		f[0]=1;
		solve(1,n);
//		for(int i=1;i<=n;i++)cout<<f[i]<<" ";
		cout<<f[n]<<endl;
	}
	return 0;
}
/*
3
15
9 1 2 11 7 15 6 8 10 5 4 12 3 14 13
5
3 2 4 1 8
10
9 1 2 4 7 3 6 8 10 5
*/
全部评论

相关推荐

已老实求offer😫:有点像徐坤(没有冒犯的意思哈)
点赞 评论 收藏
分享
球球别再泡了:坏,我单9要了14
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务