preface
这道题想了好久好久主要是菜,但其实并不是很难,大佬现在走还来得及。。。。
分析
这道题乍一看没什么想法,暴力50pts骗走溜掉。但其实那个特殊点提示很大。
对于第5个点的话,把式子化简出来就是i-l+1,i-l+2...就这个点而言,就可以开两个差分数组f,g,分别表示第i个位置的一次项系数和常数的差分。更新就变成了O(1)的。
再把差分扩展到20,也不过是个二十一阶差分嘛。然后,对于每i阶的差分来说,都要做i次才能得到真正的值,而多次差分的数列正好对应帕斯卡矩阵的r-l+1行/列,也就是杨辉三角的r-l+1列,也就是一个组合数。所以对于每个修改,在l的对应阶的差分数组上++,r+1的--,然后在r+1处向低阶减k个组合数从而保证其他阶不变。
最后更新答案时一定要从高阶往低阶更新,这样才能保证每i阶都差分了i次,注意逆元和月莫就可以了。
p.s.我用预处理帕斯卡矩阵挂了后三个点??如果你用帕斯卡矩阵过了的话请留个评论。
code
#include<bits/stdc++.h> #define ll long long #define maxn 500010 #define reg register #define mod 1000000007 using namespace std; inline void read(int &x) { x=0; reg char s=getchar(); while(s<'0' || s>'9') s=getchar(); while(s>='0' && s<='9') x=x*10+s-'0',s=getchar(); } inline void print(ll x) { if(x<0) { putchar('-'); x=-x; } if(x>9) print(x/10ll); putchar(x%10ll+'0'); } int n,m; ll a[maxn][25],b[maxn][25],inv[maxn]; void pre() { inv[1]=1; for(int i=2; i<=n; i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; } int main() { read(n),read(m); pre(); reg int l,r,k; for(reg int i=1; i<=m; i++) { read(l),read(r),read(k); a[l][k]=(a[l][k]+1)%mod; ll tmp=1,t=r-l; for(reg int j=k; ~j; j--) { a[r+1][j]=(a[r+1][j]-tmp+mod)%mod; t++; tmp=tmp*t%mod*inv[t-(r-l)]%mod; } } for(reg int i=20; ~i; i--) for(reg int j=1; j<=n; j++) b[j][i]=((a[j][i]+b[j][i+1])%mod+b[j-1][i])%mod; for(reg int i=1; i<=n; i++) print(b[i][0]),putchar('\n'); return 0; }