题解
- 组合数有一个简单的性质,C(n,k)=C(n-1,k-1)+C(n-1,k),定眼一看这不就是杨辉三角吗
- 解释一下为什么吧,现在把n分成两组分别是n-1和1,一共选k个方案数数多少,显然也就是在n-1个里选k个或在n-1个里选k-1给在加上另一组的一个
- 那么这样的话,暴力修改显然不行,思考一下,每两次操作之间是没有影响的,可以考虑一下递推来求
- 然后用差分约束,考虑一下怎么递推,由上面的公式可以发现,也就是c[i-1][j]+c[i-1][j-1]
- 那么再下一个会发现c[i-2][j]+c[i-2][j-1]+c[i-2][j-1]+c[i-2][j-2]
- 这样的话,仅仅只保留k-1是不行的,那么就可以保留0~k,然后差分约束的右端点+1也是保留0~k
- 然后计算一波递推式,答案就是b[i][0]
代码
1 #include<cstdio>
2 #include<cstring>
3 #include<string>
4 #include<algorithm>
5 #define mo 1000000007
6 #define N 500030
7 #define M 30
8 using namespace std;
9 typedef long long ll;
10 ll c[N][M],b[N][M],n,m,l,r,k;
11 void init()
12 {
13 c[0][0]=1;
14 for (ll i=1;i<=500020;i++)
15 for (ll j=0;j<=i&&j<=21;j++)
16 c[i][j]=(j!=0)?(c[i-1][j]+c[i-1][j-1])%mo:1;
17 }
18 int main()
19 {
20 freopen("sequence.in","r",stdin),freopen("sequence.out","w",stdout);
21 init();
22 scanf("%lld%lld",&n,&m);
23 for (ll i=1;i<=m;i++)
24 {
25 scanf("%lld%lld%lld",&l,&r,&k);
26 for(ll j=0;j<=k;j++) b[l][j]=(b[l][j]+c[k][k-j])%mo,b[r+1][j]=(b[r+1][j]-c[k+r-l+1][k-j])%mo;
27 }
28 for (ll i=1;i<=n;i++)
29 for (ll j=21;j>=1;j--)
30 b[i+1][j-1]=(b[i+1][j-1]+b[i][j]+b[i][j-1])%mo;
31 for(ll i=1;i<=n;i++) printf("%lld\n",(b[i][0]%mo+mo)%mo);
32 return 0;
33 }