【WOJ2325】大整数(线段树二分快速幂‘/进制模拟)

该博客讨论了如何高效地处理大整数的区间查询和修改操作,特别是在线段树和二分快速幂的基础上进行进制模拟。博主提出了一个大整数模板,允许提取整数的子段,并寻求优化这种操作的效率。问题涉及到区间加法、快速幂运算以及在处理进位时的复杂性。提供了样例输入和输出,并提到了数据约束和解决思路,包括预处理和分治策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

XXX实现了一个大整数模板(十进制) 。他的大整数有一个十分厉害的功能:它可以像提 取子串那样提取出整数中的一段。当然,这提取出的一段也是大整数。不过,XXX发现 他的模板中这种操作的效率很低,于是想请你帮他实现这样一个功能。也就是说,在给出一 个长度为 N 的大整数后,你的程序要能够快速求出大整数某一段的值。由于大整数在加减 中经常会有进位等状况发生,你的程序还需要支持区间修改操作,即将某一段中的数字全部 变成一个给定的数字。

注意:我们从大整数的最低位(最右边)开始标号,依次为第 0, 1, 2,..., N - 1 位。

输入

第一行两个整数 N,M,分别为大整数长度和操作数量。

第二行为长度为 N 的串表示初始的大整数。

接下来 M 行,每行描述一次操作。格式如下(第一个整数为操作类型) :

1 l r 表示询问[l, r]这一段的值

2 l r v 表示将[l, r]这一段中所有数字变为 v

输出

对每个询问操作输出一行一个整数表示对应的答案。由于大整数的值可以很大,输出答案对 10^9 + 7 取模后的结果即可。

样例输入

5 3
12345
1 1 3
2 1 4 3
1 1 3

样例输出

234
333

提示

数据约束

对于 40%的数据,N, M <= 5000。

对于另外 30%的数据,所有修改操作中 l = r。

对于 100%的数据,1 <= N, M <= 100000,0 <= l <= r <= N - 1, 0 <= v <= 9,大整数中每位数 字均在 0-9 的范围中。

 

 

。。。我被卡常了,明明log^2的复杂度QWQ。

其实随便优化就过了的,比如把所有1000..0%mod预处理出来。

不过博主实在太懒了,并且博主觉得这样写还可以练一练二分+快速幂,并且昨天没打完的红警诱惑着他,于是他懒得写了。

模拟一下pushup即可,对于覆盖要特殊处理,这里采用了分治的技巧

----------------------------------------

真香警告,看到那个UnAccepted太难受了,就去把它过了

#include<bits/stdc++.h>
const int N=100005;
const int mod=1e9+7;
#define re register
#define ll long long
using namespace std;
int n,m;
ll a[N];
template<class T>
inline void read(T &x)
{
	x=0; int f=1;
	static char ch=getchar();
	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();} 
	while(isdigit(ch))	x=x*10+ch-'0',ch=getchar();
	x*=f;
}
inline void write(ll x)
{
	if(x<0) { putchar('-'); x=-x;}
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
struct Tree
{
	int l,r;
	ll sum,cover;
}tree[4*N];
inline ll qpow(ll x,int y)
{
	ll ans=1,base=x;
	while(y)
	{
		if(y&1) ans=ans*base%mod; 
		base=base*base%mod;
		y>>=1;
	}
	return ans;
}
inline void pushup(int now)
{
	int y=tree[2*now+1].r-tree[2*now+1].l+1;
	tree[now].sum=(tree[2*now].sum*qpow(10,y)%mod+tree[2*now+1].sum)%mod;
}
inline void build(int now,int l,int r)
{
	tree[now].l=l; tree[now].r=r; tree[now].cover=-1;
	if(l==r)
	{
		tree[now].sum=a[l];
		return;
	}
	int m=(l+r)>>1;
	build(now<<1,l,m);
	build(now<<1|1,m+1,r);
	pushup(now);
}
inline ll Update(int l,int r,ll x)
{
	if(l==r) return x;
	int m=(l+r)>>1;
	ll lc=Update(l,m,x),rc=Update(m+1,r,x);
	return (lc*qpow(10,(r-(m+1)+1))%mod+rc)%mod;
}
inline void pushdown(int now)
{
	if(tree[now].cover==-1)	return;
	ll cover=tree[now].cover;
	tree[2*now].sum=Update(tree[2*now].l,tree[2*now].r,cover);
	tree[2*now+1].sum=Update(tree[2*now+1].l,tree[2*now+1].r,cover);
	tree[2*now].cover=tree[2*now+1].cover=cover;
	tree[now].cover=-1;
}
inline void Cover(int now,int l,int r,ll x)
{
	if(l<=tree[now].l&&tree[now].r<=r)
	{
		tree[now].sum=Update(tree[now].l,tree[now].r,x);
		tree[now].cover=x;
		return;
	}
	pushdown(now);
	int m=(tree[now].l+tree[now].r)>>1;
	if(l<=m)	Cover(now<<1,l,r,x);
	if(r>m)	Cover(now<<1|1,l,r,x);
	pushup(now);
}
struct S
{
	int l,r;
	ll sum;
};
inline S query(int now,int l,int r)
{
	if(l<=tree[now].l&&tree[now].r<=r)
	{
		S a;
		a.sum=tree[now].sum; a.l=tree[now].l; a.r=tree[now].r;
		return a;
	}
	pushdown(now);
	int m=(tree[now].l+tree[now].r)>>1;
	if(r<=m) return query(now<<1,l,r);
	if(l>m)	return query(now<<1|1,l,r);
	else
	{
		S ans1=query(now<<1,l,r),ans2=query(now<<1|1,l,r);
		S ans; ans.sum=(ans1.sum*qpow(10,ans2.r-ans2.l+1)%mod+ans2.sum)%mod; 
		ans.l=ans1.l; ans.r=ans2.r;
		return ans;
	} 
}
int main()
{
	read(n); read(m);
	for(int i=1;i<=n;i++)
	{
		char ch;
		cin>>ch;
		a[i]=ch-'0';
	}
	build(1,1,n);
	int opt,l,r;
	ll x;
	for(re int i=1;i<=m;i++)
	{
		read(opt); read(l); read(r); 
		l++; r++; int ql=l,qr=r; 
		r=n-ql+1; l=n-qr+1;
		if(opt==1) write(query(1,l,r).sum),putchar('\n');
		if(opt==2)
		{
			read(x);
			Cover(1,l,r,x);
		} 
	}
	return 0;
}
#include<bits/stdc++.h>
const int N=100005;
const int mod=1e9+7;
#define re register
#define ll long long
using namespace std;
int n,m;
ll Mo[N],a[N],num[10][N];
template<class T>
inline void read(T &x)
{
	x=0; int f=1;
	static char ch=getchar();
	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();} 
	while(isdigit(ch))	x=x*10+ch-'0',ch=getchar();
	x*=f;
}
inline void write(ll x)
{
	if(x<0) { putchar('-'); x=-x;}
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
struct Tree
{
	int l,r;
	ll sum,cover;
}tree[4*N];
//inline ll qpow(ll x,int y)
//{
//	ll ans=1,base=x;
//	while(y)
//	{
//		if(y&1) ans=ans*base%mod; 
//		base=base*base%mod;
//		y>>=1;
//	}
//	return ans;
//}
inline void pushup(int now)
{
	int y=tree[2*now+1].r-tree[2*now+1].l+1;
	tree[now].sum=(tree[2*now].sum*Mo[y]%mod+tree[2*now+1].sum)%mod;
}
inline void build(int now,int l,int r)
{
	tree[now].l=l; tree[now].r=r; tree[now].cover=-1;
	if(l==r)
	{
		tree[now].sum=a[l];
		return;
	}
	int m=(l+r)>>1;
	build(now<<1,l,m);
	build(now<<1|1,m+1,r);
	pushup(now);
}
inline ll Update(int l,int r,ll x)
{
	return num[x][r-l+1];
}
inline void pushdown(int now)
{
	if(tree[now].cover==-1)	return;
	ll cover=tree[now].cover;
	tree[2*now].sum=Update(tree[2*now].l,tree[2*now].r,cover);
	tree[2*now+1].sum=Update(tree[2*now+1].l,tree[2*now+1].r,cover);
	tree[2*now].cover=tree[2*now+1].cover=cover;
	tree[now].cover=-1;
}
inline void Cover(int now,int l,int r,ll x)
{
	if(l<=tree[now].l&&tree[now].r<=r)
	{
		tree[now].sum=Update(tree[now].l,tree[now].r,x);
		tree[now].cover=x;
		return;
	}
	pushdown(now);
	int m=(tree[now].l+tree[now].r)>>1;
	if(l<=m)	Cover(now<<1,l,r,x);
	if(r>m)	Cover(now<<1|1,l,r,x);
	pushup(now);
}
struct S
{
	int l,r;
	ll sum;
};
inline S query(int now,int l,int r)
{
	if(l<=tree[now].l&&tree[now].r<=r)
	{
		S a;
		a.sum=tree[now].sum; a.l=tree[now].l; a.r=tree[now].r;
		return a;
	}
	pushdown(now);
	int m=(tree[now].l+tree[now].r)>>1;
	if(r<=m) return query(now<<1,l,r);
	if(l>m)	return query(now<<1|1,l,r);
	else
	{
		S ans1=query(now<<1,l,r),ans2=query(now<<1|1,l,r);
		S ans; ans.sum=(ans1.sum*Mo[ans2.r-ans2.l+1]%mod+ans2.sum)%mod; 
		ans.l=ans1.l; ans.r=ans2.r;
		return ans;
	} 
}
inline void INIT()
{
	ll base=1;
	for(int i=1;i<=n;i++)
	{
		base=base*10%mod;
		Mo[i]=base;
	}
	for(int i=1;i<=9;i++)
		for(int j=1;j<=n;j++)
			num[i][j]=num[i][j-1]*10%mod+i;
}
int main()
{
	read(n); read(m);
	INIT();
	for(int i=1;i<=n;i++)
	{
		char ch;
		cin>>ch;
		a[i]=ch-'0';
	}                                      
	build(1,1,n);
	int opt,l,r;
	ll x;
	for(re int i=1;i<=m;i++)
	{
		read(opt); read(l); read(r); 
		l++; r++; int ql=l,qr=r; 
		r=n-ql+1; l=n-qr+1;
		if(opt==1) write(query(1,l,r).sum),putchar('\n');
		if(opt==2)
		{
			read(x);
			Cover(1,l,r,x);
		} 
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值