• CF1738 E. Balance Addicts


    https://codeforc.es/contest/1738/problem/E

    考虑回文的构造最典的一定是 2 边向中间不断扩展的形式,这启发我们从这个方面着手思考。

    考虑 \(f(l,r)\) 为区间 \([l,r]\) 的答案,则显然我们要选择若干组相等的前后缀和进行递归处理。

    考虑 \(a\ge 0\),所以前后缀和单不降,所以倘若 \((x,y)\),满足 \(a[l,x]=a[y,r]\),则显然不会出现,\((X,Y),X<x,Y<y\) 的情况出现,也就是说,倘若我们把当前合法二元组看成线段的话,那么显然所有线段是互相包含的。于是,我们可以找到唯一没有被包含的线段,则无论如何,一组合法的方案一定包含这个前后缀相等,因此可以将其赋值为 \(0\),计算下去即可。

    考虑可能有前后缀 \(0\) 出现,那么这个样子线段就会出现可能不包含的情况。

    于是,我们考虑能否通过计算贡献,然后计算消除前后缀 \(0\) 的答案的形式,来消除前后缀 \(0\) 的影响。

    显然,可以考虑将前后缀 \(0\) 划分成若干段即可。

    为啥正确,显然倘若划分不完,多出来的 \(0\) 对和无影响,自然归入下一部分的计算答案中了。

    #include <bits/stdc++.h>
    #define int long long
    #define pb push_back
    using namespace std;
    const int N=(int)(1e5+5),mod=998244353;
    int n,a[N],cnt[N],jie[N],djie[N];
    
    int fpow(int x,int y) {
    	int res=1; x%=mod;
    	while(y) {
    		if(y&1) res=res*x%mod;
    		y>>=1; x=x*x%mod;
    	}
    	return res;
    }
    
    int C(int n,int m) {
    	if(m>n||n<0||m<0) return 0;
    	return jie[n]*djie[m]%mod*djie[n-m]%mod;
    }
    
    int solve(int l,int r) {
    	if(l>=r) return 1;
    //	for(int i=l;i<=r;i++) {
    //		if(a[i])
    //	}
    	int L=l-1,R=r+1;
    	while(L+1<=r&&a[L+1]==0) ++L;
    	while(R-1>=l&&a[R-1]==0) --R;
    	if(L>=R) {
    		return fpow(2,r-l);
    	}
    	if(L>=l&&R<=r) {
    		int res=0,num1=L-l+1,num2=r-R+1;
    		for(int i=0;i<=min(num1,num2);i++) res=(res+C(num1,i)*C(num2,i)%mod)%mod;
    		return res*solve(L+1,R-1)%mod;
    	} else {
    		L=l-1; R=r+1;
    		int resa=0,resb=0;
    		do {
    			if(resa>=resb) --R,resb+=a[R];
    			else ++L,resa+=a[L];
    			if(L>=R) return 1;
    		} while(resa!=resb||L<l||R>r);
    //		cout<<L<<" : "<<R<<'\n';
    		if(L>=R) return 1;
    		a[L]=a[R]=0; //下面的无论如何一定选这 2 段 
    		return solve(L,R);
    	}
    }
    
    void sol() {
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	int ans=solve(1,n); ans=(ans%mod+mod)%mod;
    	cout<<ans<<'\n'; 
    }
    
    signed main() {
    	cin.tie(0); ios::sync_with_stdio(false);
    	jie[0]=djie[0]=1; for(int i=1;i<=N-5;i++) jie[i]=jie[i-1]*i%mod,djie[i]=fpow(jie[i],mod-2);
    	int T; cin>>T; while(T--) sol();
    	return 0;
    }
    
  • 相关阅读:
    RN 各种小问题
    迷宫问题的求解(回溯法、深度优先遍历、广度优先遍历)
    java 对象的初始化流程(静态成员、静态代码块、普通代码块、构造方法)
    java四种访问权限
    八大排序之归并排序
    八大排序之堆排序
    八大排序之选择排序
    八大排序之快速排序
    Java动态代理和cglib动态代理
    类加载器 ClassLoder详解
  • 原文地址:https://www.cnblogs.com/xugangfan/p/16747208.html
Copyright © 2020-2023  润新知