Codeforces 407C&408E Curious Array 组合数多层差分

本文探讨了在处理区间加操作问题时,如何巧妙运用差分技巧与组合数解决复杂算法挑战。通过深入分析,文章提供了针对特定操作的高效算法实现,包括预处理组合数、差分层数确定及结果还原过程。

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

文章目录

在退役之前,最后发几篇杂谈,就算只能再拿省二滚蛋,也要与命运抗争到底.
CF的评测机最近有点儿力不从心…
没想到做过的题又被考了一遍还是做不出,实在不甘心.

题意

给 一 个 序 列 , 有 n 次 操 作 , 每 一 次 给 [ l , r ] 加 上 C i − l + k k , 其 中 l ≤ i ≤ r . 最 后 输 出 操 作 完 的 序 列 . 给一个序列,有n次操作,每一次给[l,r]加上C_{i-l+k}^{k},其中l\leq i\leq r.\newline 最后输出操作完的序列. ,n,[l,r]Cil+kk,lir..

题解

看到先操作再询问,又是区间加之类的,想到标算应该是差分.
但是区间加组合数不同于一般的差分,我们暂时想不到有什么方法处理.
那么我们先来考虑简单的情况.
k = 0 k=0 k=0时,必然有加上的每一个数都等于 1 1 1.这时只要普通差分即可,不用多解释.
来看 k = 1 k=1 k=1时的情况,此时加上的每一个数等于 i − l + 1 , i ∈ [ l , r ] i-l+1,i\in[l,r] il+1,i[l,r],也就是区间加了一个等差数列.
区间加等差数列的情况大家想必也都知道怎么差分.
洛谷p4231 三步必杀 洛谷经典差分题,区间加等差数列,推荐大家去做一做.
我们令 a [ 1 ] [ i ] a[1][i] a[1][i]表示二层差分数组,在 a [ 1 ] [ l ] + 1 a[1][l]+1 a[1][l]+1, a [ 1 ] [ r + 1 ] − 1 a[1][r+1]-1 a[1][r+1]1,这样子二层差分的结果在 [ l , r ] [l,r] [l,r]中就等于 1 , 1 , 1 , 1 , 1 , 1... 1,1,1,1,1,1... 1,1,1,1,1,1....如果在一层再差分一次,结果就是 1 , 2 , 3 , 4 , 5 , 6... 1,2,3,4,5,6... 1,2,3,4,5,6...,这时我们再在一层的 a [ 0 ] [ r + 1 ] a[0][r+1] a[0][r+1]的地方把多出来的 r − l + 1 r-l+1 rl+1减掉,就搞定了.
根据这样的情况大胆猜想,我们对于每一次操作都要差分 k k k层.
每一次把 a [ k ] [ l ] + 1 a[k][l]+1 a[k][l]+1,然后用一个 j j j 0 0 0 k k k,分别把每一层差分从 r + 1 r+1 r+1个位置开始会多加的数给减掉.可以发现这些结果全部是组合数.
因此只要用杨辉三角或者阶乘逆元预处理组合数,每一次 O ( k ) O(k) O(k)差分,最后一遍 O ( n k ) O(nk) O(nk)处理从最后一层差分回第一层,并输出加上原数组的结果即可.
谢谢大家.
希望大家对差分的理解更深一层,也希望我对差分也能理解得更深一点.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rel register ll
#define rec register char
#define gc getchar
//#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?-1:*p1++)
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
char buf[1<<23],*p1=buf,*p2=buf;
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) pc('-'),x=-x;
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=2e5,mod=1e9+7;
typedef ll rize[yuzu|10];
rize a[115],jic={1},inv;

namespace quick{ // 快速幂等公式
ll kasumi(ll a,ll b=mod-2) {
  ll s=1;
  for (;b;b>>=1,a=a*a%mod) if (b&1) s=s*a%mod;
  return s;  
  }
void add(ll &a,ll b){if ((a+=b)>=mod) a-=mod;}
void sub(ll &a,ll b){if ((a-=b)<0) a+=mod;}
ll zuhe(int n,int m){return jic[n]*inv[m]%mod*inv[n-m]%mod;}
}using namespace quick;

void preget(int n,int i=1) { // 预处理阶乘逆元
for (;i<=n;++i) jic[i]=jic[i-1]*i%mod;
inv[n]=kasumi(jic[n]);
for (i=n-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
}

int main() {
int i,j,n,m,l,r,k;
read(n),read(m),preget(yuzu);
static rize p;
for (i=1;i<=n;++i) p[i]=read();
for (i=1;i<=m;++i) {
  l=read(),r=read(),k=read();
  add(a[k][l],1);
  for (j=0;j<=k;++j) 
    sub(a[j][r+1],zuhe(k-j+r-l,k-j)); // 稍微算一下,可以发现每一层多加的数也是组合数.
  }
for (i=100;~i;--i)
  for (j=1;j<=n;++j) 
    a[i][j]=(a[i][j]+a[i+1][j]+a[i][j-1])%mod;
for (i=1;i<=n;++i) write((a[0][i]+p[i])%mod),p32;
}
### 回答1: Codeforces估分是指在Codeforces比赛中预估自己在比赛结束后所能获得的分数。这个分数是考虑根据自己的表现和其他参赛者的表现来预估的。 Codeforces分数是根据比赛中的排名和成功解决问题的数量来计算的。在每场比赛结束后,每位参赛者会根据其在比赛中的表现被分配一个分数。比赛中排名越高的参赛者获得的分数也越高,而解决更多问题的参赛者同样也能获得更多分数。 Codeforces估分有两种方法:一种是通过比赛中的实时排名来估计当前分数,另一种是通过计算比赛中已解决问题的分数来估计最终的总分。 对于第一种方法,我们可以在比赛过程中观察自己在排名榜上的位置和其他参赛者的分数。如果自己的排名越高,说明自己的分数也会越高;如果其他人的分数与自己相差较大,说明他们可能已经解决了更多的问题,因此可能获得更高的分数。 对于第二种方法,我们可以根据已经解决的问题数量来估算总分。Codeforces的比赛系统会根据每个问题的难度和重要性分配不同的分数。因此,如果我们能成功解决更多的问题,我们也将获得更高的分数。 总的来说,Codeforces估分是一个根据比赛中的排名和解决问题的数量来估计自己分数的过程。但是,由于每场比赛的题目和参赛人数不同,预估分数可能有一定的不确定性。因此,我们建议在比赛过程中持续观察排名榜和其他参赛者的情况,以及时作出调整和优化自己的策略。 ### 回答2: Codeforces是一个在线的编程竞赛平台,每个竞赛都有一定的难度,需要通过编写代码来解决各种算法和数据结构的问题。Codeforces的估分指的是根据你在竞赛中的表现得出的一个评分。 在Codeforces竞赛中,你会根据你的解题情况和提交的答案是否正确来获得分数。每个问题都有一定的分值,解决该问题可以获得该分值的分数。如果你的答案是正确的,你将获得该问题的分数;如果你的答案是错误的,你将不会获得分数。 Codeforces的估分算法是基于Elo算法改进的。Elo算法是一种用于评估竞技选手水平的算法。该算法会根据你的表现和对手的水平来决定你的分数变化。如果你击败了一个分数比你高的选手,你的分数可能会上升得更多;如果你输给一个分数比你低的选手,你的分数可能会下降得更多。 Codeforces的估分也考虑了竞赛的参与人数。如果你在一个参与人数多的竞赛中获得了好的成绩,你的分数可能会得到进一步的提升。相反,如果你在一个参与人数少的竞赛中获得了好的成绩,你的分数可能会得到更少的提升。 总的来说,Codeforces的估分是根据你的表现、对手的水平和竞赛的参与人数来计算的。通过持续参与竞赛并取得好的成绩,你的分数将会逐渐提升。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值