Atcoder ACL Beginner Contest

D.Flat Subsequence
f[i]表示:数列最后一个为第i个的最大值,它可以由之前的,数值差绝对值在m以内的若干个f[j]转移而来。
所以我们用一棵线段树,在a[j]的位置上把f[j]存下来,然后对于第i个值来说,只要查询:[max(a[i]-m,0),min(a[i]+m,300000)]区间内的最大f值即可。
#include <bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,m,l,r,mid,ans;
int maxn[N<<2],a[N],f[N];

void change(int k,int l,int r,int pos,int v)
{
	if (l==pos && pos==r)
	{
		maxn[k]=v;
		return;
	}
	int mid=l+r>>1;
	if (pos<=mid) change(k<<1,l,mid,pos,v);
	else change(k<<1|1,mid+1,r,pos,v);
	maxn[k]=max(maxn[k<<1],maxn[k<<1|1]); 
}

int query(int k,int l,int r,int qx,int qy)
{
	if (qx<=l && r<=qy) return maxn[k];
	int mid=l+r>>1;
	int ans=0;
	if (qx<=mid) ans=max(ans,query(k<<1,l,mid,qx,qy));
	if (mid<qy) ans=max(ans,query(k<<1|1,mid+1,r,qx,qy));
	return ans;
}

int main(){
	scanf("%d%d",&n,&m);
	for (register int i=1; i<=n; ++i) scanf("%d",&a[i]);	
	f[1]=1;
	change(1,0,3e5,a[1],f[1]);	
	for (register int i=2; i<=n; ++i)
	{
		int now=query(1,0,3e5,max(a[i]-m,0),min(a[i]+m,300000));
		f[i]=max(1,now+1);
		now=query(1,0,3e5,a[i],a[i]);
		if (f[i]>now) change(1,0,3e5,a[i],f[i]);
	}
	for (register int i=1; i<=n; ++i) ans=max(ans,f[i]);
	printf("%d\n",ans);
return 0;	
}
E.Replace Digits
预处理i个1,i个2…i个9的值,和1,10,100…的值。
然后就线段树区间赋值后,得到num[1]即可。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,MOD=998244353;
int n,q,l,r,v;
int ll[N<<2],rr[N<<2],num[N<<2],sum[10][N],add[N<<2],bin[N];
	
void build(int k,int l,int r)
{

	ll[k]=l; rr[k]=r;
	if (l==r)
	{
		num[k]=1;
		return;
	}
	int mid=l+r>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	num[k]=(num[k<<1]*bin[rr[k<<1|1]-ll[k<<1|1]+1]%MOD+num[k<<1|1])%MOD;	
}
inline void pushdown(int k)
{
	if (add[k])
	{
		num[k<<1]=sum[add[k]][rr[k<<1]-ll[k<<1]+1];
		num[k<<1|1]=sum[add[k]][rr[k<<1|1]-ll[k<<1|1]+1];
		add[k<<1]=add[k<<1|1]=add[k];
		add[k]=0;
	}
}
void change(int k,int l,int r,int qx,int qy,int v)
{
	if (qx<=l && r<=qy)
	{
		num[k]=sum[v][r-l+1];
		add[k]=v;
		return;
	}
	pushdown(k);
	int mid=l+r>>1;
	if (qx<=mid) change(k<<1,l,mid,qx,qy,v);
	if (mid<qy) change(k<<1|1,mid+1,r,qx,qy,v);
	num[k]=(num[k<<1]*bin[rr[k<<1|1]-ll[k<<1|1]+1]%MOD+num[k<<1|1])%MOD;
}
	
signed main(){
	scanf("%lld%lld",&n,&q);
	bin[0]=1;
	for (register int i=1; i<=n; ++i) bin[i]=bin[i-1]*10%MOD;
	for (register int i=1; i<=9; ++i)
	{
		sum[i][1]=i;
		for (register int j=2; j<=n; ++j) sum[i][j]=(sum[i][j-1]*10%MOD+i)%MOD;
	}
	build(1,1,n);
	for (register int i=1; i<=q; ++i) 
	{
		scanf("%lld%lld%lld",&l,&r,&v);
		change(1,1,n,l,r,v);
		printf("%lld\n",num[1]);
	}
return 0;	
}
F.Heights and Pairs
菜菜不会多项式…
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值