首页 > 其他分享 >组合数学专项训练记录

组合数学专项训练记录

时间:2024-03-05 19:35:40浏览次数:32  
标签:专项 val 训练 int res ll 数学 id mod

[abc221_e]LEQ

依题意得,当确定了两个端点后,中间的可选可不选,考虑枚举左端点,找比它大的右端点,求方案数,时间复杂度\(O(n^2)\),显然会T

考虑优化,若两个端点分别是i,j,则方案数为\(2^{j-i-1}=2^j\div 2^{i+1}\),所以考虑权值线段树记录\(2^j\),倒序枚举左端点即可

代码:

#include<cstdio>
#define ll long long
using namespace std;
const int p=1e9,mod=998244353;
int n,a[300005];
int ls[5000005],rs[5000005],idx,rt;
ll val[5000005];
ll qpow(ll x,int y)
{
	ll res=1;
	while(y)
	{
		if(y&1) res=res*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return res;
}
int add(int id,int l,int r,int x,int v)
{
	if(!id) id=++idx;
	if(l==r)
	{
		val[id]=(qpow(2,v)+val[id])%mod;
		return id;
	}
	int mid=(l+r)>>1;
	if(x<=mid) ls[id]=add(ls[id],l,mid,x,v);
	else rs[id]=add(rs[id],mid+1,r,x,v);
	val[id]=(val[ls[id]]+val[rs[id]])%mod;
	return id;
}
ll query_val(int id,int l,int r,int ql,int qr)
{
	if(!id||l>qr||r<ql) return 0;
	if(l>=ql&&r<=qr)
	{
		return val[id];
	}
	int mid=(l+r)>>1;
	ll res=0;
	if(mid>=ql) res=query_val(ls[id],l,mid,ql,qr);
	if(mid<qr) res=(res+query_val(rs[id],mid+1,r,ql,qr))%mod;
	return res%mod;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	ll ans=0;
	for(int i=n;i>0;i--)
	{
		ll cnt=query_val(rt,1,p,a[i],p);
	//	printf("%d ",cnt);
		ans=(ans+cnt*qpow(qpow(2,i+1),mod-2)%mod)%mod;
		rt=add(rt,1,p,a[i],i);
	}
	printf("%lld",ans%mod);
	return 0;
}

标签:专项,val,训练,int,res,ll,数学,id,mod
From: https://www.cnblogs.com/wangsiqi2010916/p/18054723

相关文章