【JZOJ5922】sequence

本文探讨了在m个区间内进行加法和组合数操作的算法解决方案,具体介绍了如何通过差分和前缀和技巧高效计算每个元素的最终值。针对不同情况,文章提供了详细的代码实现和解释。

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

Description

有m个区间加组合数操作,对于l≤i≤rl\leq i\leq rlir,给aia_iai加上Ci−l+kkC_{i-l+k}^kCil+kkaia_iai初始为0,k&lt;=20k&lt;=20k<=20。问最后所有aia_iai的值。

Solution

做法很多。
可以对kkk分类,对于每个kkk,执行区间加的一个区间[l,r][l,r][l,r]的每个iii相当于加上一个关于iiikkk次多项式,我们把多项式的系数求出来,那么区间操作相当于将这些系数进行累加,可以用差分,在lll处打上这些系数,在r+1r+1r+1减去,最后只用求前缀和即可。

其实我们发现,对于一个三元组(l,r,x)(l,r,x)(l,r,x),如果r=nr=nr=n,我们开一个k×nk\times nk×n的数组bbb,在bk,lb_{k,l}bk,l+1+1+1,最后向上向右做前缀和,b0,ib_{0,i}b0,i就是答案,可以理解成为一个从(k,l)(k,l)(k,l)位置开始的向右上方的杨辉三角。对于r&lt;nr&lt;nr<n我们只要在每个bi,r+1b_{i,r+1}bi,r+1减去相应的值即可。实际上就是维护k阶差分。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=5e5+50,mo=1e9+7;
ll c[N][22],b[N][22];
ll pow(ll x,int y){
	ll b=1;
	for(;y;y>>=1,x=x*x%mo) if(y&1) b=b*x%mo;
	return b;
}
int main()
{
	freopen("sequence.in","r",stdin);
	freopen("sequence.out","w",stdout);
	int n,m;
	scanf("%d %d",&n,&m);
	c[0][0]=1;
	fo(i,1,n+20){
		c[i][0]=1;
		fo(j,1,20) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
	}
	while(m--){
		int l,r,k;
		scanf("%d %d %d",&l,&r,&k);
		b[l][k]++;
		fo(i,0,k) b[r+1][k-i]=(b[r+1][k-i]-c[r-l+i][i]+mo)%mo;
	}
	fd(j,20,0)
	fo(i,1,n) b[i][j]=(b[i][j]+b[i-1][j]+b[i][j+1])%mo;
	fo(i,1,n) printf("%lld\n",b[i][0]);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值