【JZOJ5922】sequence

xiaoxiao2022-06-11  39

Description

有m个区间加组合数操作,对于 l ≤ i ≤ r l\leq i\leq r lir,给 a i a_i ai加上 C i − l + k k C_{i-l+k}^k Cil+kk a i a_i ai初始为0, k < = 20 k<=20 k<=20。问最后所有 a i a_i ai的值。

Solution

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

其实我们发现,对于一个三元组 ( l , r , x ) (l,r,x) (l,r,x),如果 r = n r=n r=n,我们开一个 k × n k\times n k×n的数组 b b b,在 b k , l b_{k,l} bk,l + 1 +1 +1,最后向上向右做前缀和, b 0 , i b_{0,i} b0,i就是答案,可以理解成为一个从 ( k , l ) (k,l) (k,l)位置开始的向右上方的杨辉三角。对于 r < n r<n r<n我们只要在每个 b i , r + 1 b_{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]); }
转载请注明原文地址: https://www.6miu.com/read-4930520.html

最新回复(0)