牛客练习赛48----C-小w的糖果

首先发出题目链接:
链接:https://ac.nowcoder.com/acm/contest/923/C
来源:牛客网
涉及:树状数组


题目如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对题目进行归纳:
 1.type=1时发糖果的人为tokitsukaze,若从pos开始往后发糖,则后面所有人的糖全部+1,与每个人的位置无关。
 
 2.type=2时发糖果的人为teito,若从pos开始发糖,则第x(x>=pos)个位置的人获得 x − p o s + 1 x-pos+1 xpos+1个糖。
 
 3.type=3时发糖果的人为winterzz1,若从pos开始发糖,则第x(x>=pos)个人获得 ( x − p o s + 1 ) 2 (x-pos+1)^{2} (xpos+1)2个糖,且 ( x − p o s + 1 ) 2 = x 2 + ( 2 − 2 ∗ p o s ) x + p o s 2 − 2 ∗ p o s + 1 (x-pos+1)^{2}=x^{2}+(2-2*pos)x+pos^{2}-2*pos+1 (xpos+1)2=x2+(22pos)x+pos22pos+1
 
 
可以发现,第x个人的糖果都可以由一个多项式来表示:
f ( x ) = A x x 2 + B x x + C x f(x)=A_{x}x^{2}+B_{x}x+C_{x} f(x)=Axx2+Bxx+Cx

同时还可以发现,每次发糖,都只修改了多项式系数 A x A_{x} Ax, B x B_{x} Bx, C x C_{x} Cx


 当type=1时:从pos位置后的所有 C x C_{x} Cx全部加1
 
 当type=2时:从pos位置后的所有 C x C_{x} Cx全部加 ( 1 − p o s ) (1-pos) (1pos),所有的 B x B_{x} Bx全部加1
 
 当type=3时:从pos位置后的所有 C x C_{x} Cx全部加 ( p o s 2 − 2 ∗ p o s + 1 ) (pos^{2}-2*pos+1) (pos22pos+1),所有的 B x B_{x} Bx全部加 ( 2 − 2 ∗ p o s ) (2-2*pos) (22pos),所有的 A x A_{x} Ax1


每一次操作,还需要将每个人的糖果数输出出来;每次修改,都要修改一个区间的所有糖果数。

于是,我们只要维护差分数列就可以实现树状数组区间修改,用三个数组分别维护三个系数 A x A_{x} Ax, B x B_{x} Bx, C x C_{x} Cx

树状数组维护差分序列进行区间修改的操作可以看这个博客

下面是对于题目中type的三种操作,对于的树状数组维护操作代码:

if(type==1){
	add(tree[1],1,pos);
}
else if(type==2){
	add(tree[1],1-pos,pos);
	add(tree[2],1,pos);
}
else{
	add(tree[1],1-2*pos%mod+(ll)pos*(ll)pos%mod,pos);//pos是int类型,这里pos*pos可能会爆,所以要强制类型转换一下,然后取模
	add(tree[2],2-2*pos%mod,pos);
	add(tree[3],1,pos);
}	

每一次输出所有人的糖果数,相当于多次单点查询,然后差分数组的前n项和刚好相当于单点查询,第i个人的糖果数是 A i i 2 + B i i + C i A_{i}i^{2}+B_{i}i+C_{i} Aii2+Bii+Ci

for(i=1;i<=n;i++){
	ll sumn=0;
	sumn+=sum(tree[1],i)%mod;
	sumn+=sum(tree[2],i)%mod*i%mod;
	sumn+=sum(tree[3],i)%mod*i%mod*i%mod;
	printf("%d ",(sumn+mod)%mod);
}

举个例子:
稍后举


代码如下:

#include <iostream>
#include <cstring>
#define mod (ll)1000000007
using namespace std;
typedef long long ll;
ll tree[4][100005];
int n,m,type,pos;
int lowerbit(int x){
	return x&-x;
}
void add(ll tr[],ll z,int v){//树状数组单点修改
	int i;
	for(i=v;i<=n;i+=lowerbit(i))
		tr[i]=(tr[i]+z)%mod;
	return;
}
ll sum(ll tr[],int v){//树状数组区间查询
	int i;
	ll sum=0;
	for(i=v;i>0;i-=lowerbit(i))
		sum=(sum+tr[i])%mod;
	return sum;
}
int main(){
	int t,i;
	cin>>t;
	while(t--){
		memset(tree,0,sizeof(tree));//每一次先把树状数组清零
		scanf("%d%d",&n,&m);
		for(i=1;i<=m;i++){
			scanf("%d%d",&type,&pos);
			//下面按照三种情况维护系数树状数组
			if(type==1){
				add(tree[1],1,pos);
			}
			else if(type==2){
				add(tree[1],1-pos,pos);
				add(tree[2],1,pos);
			}
			else{
				add(tree[1],1-2*pos%mod+(ll)pos*(ll)pos%mod,pos);
				add(tree[2],2-2*pos%mod,pos);
				add(tree[3],1,pos);
			}	
		}
		for(i=1;i<=n;i++){
			ll sumn=0;
			//下面求多项式的值
			sumn+=sum(tree[1],i)%mod;
			sumn+=sum(tree[2],i)%mod*i%mod;
			sumn+=sum(tree[3],i)%mod*i%mod*i%mod;
			printf("%d ",(sumn+mod)%mod);
		}
		printf("\n");
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值