洛谷题面传送门

我竟然独立切掉了这道题!incredible!

纪念我逝去的一上午(NOIP 总时长 4.5h,这题做了我整整 4.5h)

首先讲一下现场我想的 80 分的做法,虽然最后挂成了 65 分,但大概率是被卡常了(

注意到虽然点数高达 \(\prod\limits_{i=1}^kw_i\),但每一维我们都可以单独考虑,具体来说,我们设 \(tim_{i,j}\) 表示只考虑 \(c_k=i\) 的 \(k\),当前第 \(i\) 维坐标是 \(j\),最少需要多少步才能离开场地,\(tim_{i,j}\) 显然 xjb 分类讨论就能求出。那么由于每一维的独立性,对于一个坐标 \((x_1,x_2,\cdots,x_k)\),它所需要的离开场地的最小时间就是对应每一维所需时间取 \(\min\),即 \(\min\limits_{i=1}^ktim_{i,x_i}\),也就是说我们要求的东西就是 \(\sum\limits_{x_i\le w_i}\min\limits_{i=1}^ktim_{i,x_i}\),我们考虑将 \(tim_{i,j}\) 全部揉在一起从大到小排序并枚举 \(\min\limits_{i=1}^ktim_{i,x_i}=tim_{x,y}\),那么此时合法的坐标数目就是 \(\prod\limits_{j\ne x}cnt_j\),其中 \(cnt_j=\sum\limits_{k=1}^{w_j}[tim_{j,k}>tim_{x,y}]\),这个值可以通过预处理逆元在枚举的过程中 \(\mathcal O(1)\) 求得。那么,加上排序的复杂度,总复杂度大概是 \(nk\log nk\)。然鹅这个复杂度不开 O2 是过不去的,有我现场写的程序为证。因此考虑加点小小的剪枝,注意到 \(tim_{i,j}\) 随着 \(j\) 的增大是一个凸函数,因此咱考虑找到该函数的峰点,然后将两部分归并起来即可在 \(\mathcal O(w_i)\) 的时间内将某个 \(tim_{i}\) 从大到小排序,然后再将所有 \(tim_i\) 再归并起来即可。然鹅有一个让人非常哭笑不得的细节,就是在对全部 \(k\) 个数组归并时,找最小值用 priority_queue,时间复杂度 \(\mathcal O(nk\log k)\) 反而 TLE,改成暴力 \(\mathcal O(k)\) 找反而就过了,大概是常数的问题吧。

附:80 分的代码:

const int MAXN=5e5;
const int MAXK=10;
const int MOD=1e9+7;
int n,k,c[MAXN+5],d[MAXN+5],w[MAXK+2];
namespace sub1{
bool check(){
int flg=1;
for(int i=1;i<=k;i++) flg&=(w[i]<=1e6);
return flg;
}
const int MAXW=1e6;
const ll INF=0x3f3f3f3f3f3f3f3fll;
ll tim[MAXK+2][MAXW+5];
int lft[MAXW+5],rit[MAXW+5];
void calc(int x){
memset(lft,0,sizeof(lft));memset(rit,0,sizeof(rit));
int mn=0,mx=0,cur=0;
for(int i=1;i<=n;i++) if(c[i]==x) cur+=d[i];
if(cur<0){
for(int i=1;i<=n;i++) if(c[i]==x) d[i]=-d[i];
} cur=0;
for(int i=1;i<=n;i++) if(c[i]==x){
cur+=d[i];
if(cur>mx) rit[cur]=i,mx=cur;
if(cur<mn) lft[-cur]=i,mn=cur;
}
for(int i=1;i<=w[x];i++){
tim[x][i]=INF;
if(i+mn<=0) chkmin(tim[x][i],(ll)lft[i]);
if(i+mx>w[x]) chkmin(tim[x][i],(ll)rit[w[x]+1-i]);
if(cur){
int bound=w[x]-mx+1;
int tt=max((bound-i+cur-1)/cur,0);
chkmin(tim[x][i],1ll*tt*n+rit[w[x]+1-(i+tt*cur)]);
}
}
} ll A[MAXW+5],B[MAXW+5];
int inv[MAXW+5];
void mergesort(int x){
int ps=0,c1=0,c2=0;
for(int i=1;i<=w[x];i++) if(tim[x][i]>tim[x][i+1]){ps=i;break;}
for(int i=ps;~i;i--) A[++c1]=tim[x][i];A[c1+1]=0;
for(int i=ps+1;i<=w[x];i++) B[++c2]=tim[x][i];B[c2+1]=0;
for(int i=1,p1=1,p2=1;i<=w[x];i++){
if(A[p1]>B[p2]) tim[x][i]=A[p1++];
else tim[x][i]=B[p2++];
}
}
int cnt[MAXK+5];
void solve(){
for(int i=1;i<=k;i++) calc(i);
for(int i=1;i<=k;i++) mergesort(i);
for(int i=(inv[0]=inv[1]=1)+1;i<=MAXW;i++)
inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
int sm=0;for(int i=1;i<=k;i++) sm+=w[i];
bool flg=1;
for(int i=1;i<=k;i++) flg&=(tim[i][1]==INF);
if(flg) return puts("-1"),void();
int res=1,cnt0=k,ans=0;
for(int i=1;i<=sm;i++){
int x=0;
for(int j=1;j<=k;j++) if(tim[j][cnt[j]+1]>tim[x][cnt[x]+1]) x=j;
if(!cnt[x]) cnt0--;
else res=1ll*res*inv[cnt[x]]%MOD*(cnt[x]+1)%MOD;
++cnt[x];
if(!cnt0&&tim[x][cnt[x]]) ans=(ans+tim[x][cnt[x]]%MOD*res%MOD*inv[cnt[x]])%MOD;
} printf("%d\n",ans);
}
}
int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
if(sub1::check()) sub1::solve();
return 0;
}

接下来考虑正解,也就是这个脑子不太好使的人今早灵机一动想出来的做法。

我们考虑预处理出这样几个量:

  • \(x_i\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么在一个周期中第 \(i\) 维坐标的最小值是多少。
  • \(y_i\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么在一个周期中第 \(i\) 维坐标的最大值是多少。
  • \(t_i\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么在一个周期结束后第 \(i\) 维的坐标是多少。方便起见我们假设 \(t_i\ge 0\),如果 \(t_i<0\) 那我们只需将 \(c_j=i\) 的 \(d_j\) 都变为其相反数即可。
  • \(mn_{i,j}\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么执行完前 \(j\) 个命令后,在一个周期中第 \(i\) 维坐标的最小值是多少,不难发现 \(x_i=mn_{i,n}\)。
  • \(mx_{i,j}\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么执行完前 \(j\) 个命令后,在一个周期中第 \(i\) 维坐标的最大值是多少,同样地有 \(y_i=mx_{i,n}\)。
  • \(sum_{i,j}\):在一整个长度为 \(n\) 周期中,如果我们将起点视为源点,那么执行完前 \(j\) 个命令后,第 \(i\) 维的坐标是多少。

首先我们思考一下对于某一维 \(i\) 上的某个坐标 \(x\),最少需要多少步才能离开这一维的范围(即,这一维的坐标 \(\notin[1,w_i]\))。一个比较显然但非常关键的性质是,由于 \(t_i\ge 0\),因此如果第一个周期内不能从左边离开场地,那么第二周期起点位置肯定比第一周期更靠右,也就更不可能从右边离开场地,也就是说如果离开时走的步数 \(>n\),那么我们必定是从右边离开场地的。因此我们考虑枚举小 C 最后一步是在这个长度为 \(n\) 的周期中哪个指令下离开场地,记为第 \(i\) 个命令。那么此时此刻已经执行的命令必定是若干个长度为 \(n\) 的完整的周期加上前 \(i\) 个命令构成的这段前缀,我们记当前位于第 \(K\) 个周期(方便起见我们不妨设 \(K\ge 2\),\(K=1\) 的情况后面再说),那么根据之前的推论,这一步肯定是第 \(c_i\) 维坐标达到了 \(w_{c_i}+1\)。又因为第一周期内无法离开场地,因此如果我们记 \(s_i\) 为第 \(i\) 起点的坐标,必定有 \(s_j\in[-x_j+1,w_j]\),又因为在前 \((K-1)n+i-1\) 步内不能离开场地,因此对于每一维 \(j\) 可以列出以下四个不等式:

\[\begin{cases}
s_j+(K-2)t_j+mn_{j,i-1}\in[1,w_j]\\
s_j+(K-2)t_j+mx_{j,i-1}\in[1,w_j]\\
s_j+(K-1)t_j+x_j\in[1,w_j]\\
s_j+(K-1)t_j+y_j\in[1,w_j]
\end{cases}
\]

再加上第 \(i\) 步第 \(c_i\) 维坐标需达到 \(w_{c_i}+1\),因此还有 \(s_{c_i}+(K-1)t_{c_i}+sum_{c_i,i-1}=w_{c_i}+1\)。

总共是 \(5k+1\) 个限制,每个限制都可以表示为 \(s_j\in[L,R]\) 的形式,因此我们可以解出 \(s_j\) 的范围,如果存在某个 \(s_j\) 的范围为空则表明不可能恰好在第 \((K-1)n+i\) 步离开场地,否则合法的坐标数就是 \(s_j\) 范围的乘积。

但是直接枚举 \(K\) 复杂度过高,无法接受。不过注意到一个性质就是如果存在某个坐标经过 \(Kn+i\) 步离开场地,就必定存在某个坐标经过 \((K-1)n+i\) 步离开场地,因此考虑二分最大的 \(K\) 满足存在某个坐标经过 \((K-1)n+i\) 步离开场地,那么我们要求的值就是 \(\sum\limits_{j=2}^K\text{calc}((j-1)n+i)·((j-1)n+i)\),其中 \(\text{calc}(x)\) 为满足恰好经过 \(x\) 步离开场地的坐标个数。暴力算还是 T,不过我们还可以发现,每次解出来的 \(s_j(j\ne c_i)\) 的范围区间的左端点都是固定不变的值 \(-x_j+1\),因此区间长度可以写成关于右端点的一次函数,又区间非空,因此右端点可以写成关于 \(K\) 的一次函数,因此 \(\text{calc}((j-1)n+i)\) 可以看作关于 \(j\) 的 \(k-1\) 次函数,再加上前缀和与后面的系数,\(\sum\) 里的东西为关于 \(K\) 的 \(k+1\) 次函数,因此可以考虑求出 \(2,3,\cdots,k+3\) 处的函数值然后把多项式插出来即可。

接下来考虑 \(K=1\) 的情况,相信聪明的读者们如果理解了 \(K\ge 2\) 的情况,那么 \(K=1\) 的情况想必是易如反掌了,我们还是可以列出一些关于 \(s_j\) 的不等式,也就能解出对应 \(s_j\) 的范围,然后可以乘法原理对应的坐标个数,如果还是不懂那就看代码吧。

上述算法复杂度是 \(nk\log n+nk^2\),不开 O2 只能获得 80 分的好成绩。

附:不开 O2 80pts,开 O2 AC 的代码:

namespace sub2{
int x[MAXK+2],y[MAXK+2],t[MAXK+2];
int mn[MAXK+2][MAXN+5],mx[MAXK+2][MAXN+5],sum[MAXK+2][MAXN+5];
void calc(int r){
for(int i=1;i<=n;i++) if(c[i]==r) t[r]+=d[i];
if(t[r]<0){
t[r]=-t[r];
for(int i=1;i<=n;i++) if(c[i]==r) d[i]=-d[i];
} int cur=0;
for(int i=1;i<=n;i++){
if(c[i]==r) cur+=d[i];sum[r][i]=cur;
mn[r][i]=min(mn[r][i-1],cur);
mx[r][i]=max(mx[r][i-1],cur);
} x[r]=mn[r][n];y[r]=mx[r][n];
// printf("%d %d\n",x[r],y[r]);
}
struct itvl{
ll l,r;
itvl(ll _l=0,ll _r=0):l(_l),r(_r){}
itvl operator &(const itvl &rhs){
return itvl(max(l,rhs.l),min(r,rhs.r));
}
};
int calc(int mid,int id){
static itvl it[MAXK+2];
for(int i=1;i<=k;i++) it[i]=itvl(-x[i]+1,w[i]);
for(int i=1;i<=k;i++){
it[i]=it[i]&itvl(1-1ll*(mid-2)*t[i]-y[i],w[i]-1ll*(mid-2)*t[i]-y[i]);
it[i]=it[i]&itvl(1-1ll*(mid-1)*t[i]-mx[i][id-1],w[i]-1ll*(mid-1)*t[i]-mx[i][id-1]);
} it[c[id]]=it[c[id]]&itvl(w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id],w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id]);
// printf("checking %d %d\n",mid,id);
// for(int i=1;i<=k;i++) printf("%lld %lld\n",it[i].l,it[i].r);
int res=1;
for(int i=1;i<=k;i++){
if(it[i].l>it[i].r) return 0;
res=1ll*res*(it[i].r-it[i].l+1)%MOD;
} return res;
}
int ff[10],inv[10];
void solve(){
for(int i=(inv[0]=inv[1]=1)+1;i<=6;i++) inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=k;i++) calc(i);
// for(int i=1;i<=k;i++) printf("%d %d %d\n",x[i],y[i],t[i]);
int res=0;
for(int i=1;i<=n;i++) if(d[i]==1){
int l=2,r=1e9,p=-1;
if(calc(1e9+1,i)) return puts("-1"),void();
while(l<=r){
int mid=l+r>>1;
if(calc(mid,i)) p=mid,l=mid+1;
else r=mid-1;
} //printf("%d\n",p);
if(~p){
for(int j=2;j<=min(p,6);j++){
// printf("%d %d %d\n",j,i,calc(j,i));
ff[j]=1ll*calc(j,i)*(1ll*(j-1)*n%MOD+i)%MOD;
ff[j]=(ff[j-1]+ff[j])%MOD;
} if(p<=6) res=(res+ff[p])%MOD;
else{
for(int j=2;j<=6;j++){
int ss=1;
for(int k=2;k<=6;k++) if(j^k){
int mul=1ll*(p-k+MOD)*inv[abs(j-k)]%MOD;
if(j<k) mul=MOD-mul;ss=1ll*ss*mul%MOD;
} res=(res+1ll*ss*ff[j])%MOD;
}
}
}
}
for(int i=1;i<=n;i++){
static itvl it[MAXK+2];
for(int j=1;j<=k;j++) it[j]=itvl(1,w[j]);
for(int j=1;j<=k;j++){
it[j]=it[j]&itvl(1-mn[j][i-1],w[j]-mn[j][i-1]);
it[j]=it[j]&itvl(1-mx[j][i-1],w[j]-mx[j][i-1]);
} if(!~d[i]){
it[c[i]]=it[c[i]]&itvl(0-sum[c[i]][i],0-sum[c[i]][i]);
} else {
it[c[i]]=it[c[i]]&itvl(w[c[i]]+1-sum[c[i]][i],w[c[i]]+1-sum[c[i]][i]);
} int mul=i;
// printf("%d:\n",i);
// for(int j=1;j<=k;j++) printf("%lld %lld\n",it[j].l,it[j].r);
for(int j=1;j<=k;j++){
if(it[j].l>it[j].r) mul=0;
else mul=1ll*mul*(it[j].r-it[j].l+1)%MOD;
} res=(res+mul)%MOD;
}
printf("%d\n",res);
}
}
int main(){
// freopen("walk4.in","r",stdin);
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
if(sub1::check()) sub1::solve();
else sub2::solve();
return 0;
}

接下来考虑加点优化,显然复杂度瓶颈在于二分,注意到在二分检验的过程中,我们要用到很多不等式,不过这些不等式都可以写成 \(s_j\in[1-Kt_j+B,w_j-Kt_j+B]\) 的形式,又根据之前的推理这些区间的交的左端点恰好是 \(-x_j+1\),因此我们只用考虑右端点的限制,即 \(B\) 最小的限制即可,由于这些区间的交集非空,必然可以得到 \(w_j-Kt_j+B\ge -x_j+1\),移个项可以得到 \(Kt_j\le w_j+B+x_j-1\),解得 \(K\le\lfloor\dfrac{w_j+B+x_j-1}{t_j}\rfloor\),也就是说这些限制归结到底都可以写成 \(K\le X\) 的形式,然后对这些 \(X\) 取个 \(\min\) 即可得到 \(K\) 的最大值,这样就省去了二分的 \(\log\)。

还有就是上面的代码中插值用了暴力 \(k^2\) 的插值方法,不过由于下标连续,可以 \(\mathcal O(k)\) 插值,这样常数会小不少。

最后附上我最后一次提交的完整代码,开了 O2 只需 947ms:

const int MAXN=5e5;
const int MAXK=10;
const int MOD=1e9+7;
int n,k,c[MAXN+5],d[MAXN+5],w[MAXK+2];
namespace sub1{
bool check(){
int flg=1;
for(int i=1;i<=k;i++) flg&=(w[i]<=1e6);
return flg;
}
const int MAXW=1e6;
const ll INF=0x3f3f3f3f3f3f3f3fll;
ll tim[MAXK+2][MAXW+5];
int lft[MAXW+5],rit[MAXW+5];
void calc(int x){
memset(lft,0,sizeof(lft));memset(rit,0,sizeof(rit));
int mn=0,mx=0,cur=0;
for(int i=1;i<=n;i++) if(c[i]==x) cur+=d[i];
if(cur<0){
for(int i=1;i<=n;i++) if(c[i]==x) d[i]=-d[i];
} cur=0;
for(int i=1;i<=n;i++) if(c[i]==x){
cur+=d[i];
if(cur>mx) rit[cur]=i,mx=cur;
if(cur<mn) lft[-cur]=i,mn=cur;
}
for(int i=1;i<=w[x];i++){
tim[x][i]=INF;
if(i+mn<=0) chkmin(tim[x][i],(ll)lft[i]);
if(i+mx>w[x]) chkmin(tim[x][i],(ll)rit[w[x]+1-i]);
if(cur){
int bound=w[x]-mx+1;
int tt=max((bound-i+cur-1)/cur,0);
chkmin(tim[x][i],1ll*tt*n+rit[w[x]+1-(i+tt*cur)]);
}
}
} ll A[MAXW+5],B[MAXW+5];
int inv[MAXW+5];
void mergesort(int x){
int ps=0,c1=0,c2=0;
for(int i=1;i<=w[x];i++) if(tim[x][i]>tim[x][i+1]){ps=i;break;}
for(int i=ps;~i;i--) A[++c1]=tim[x][i];A[c1+1]=0;
for(int i=ps+1;i<=w[x];i++) B[++c2]=tim[x][i];B[c2+1]=0;
for(int i=1,p1=1,p2=1;i<=w[x];i++){
if(A[p1]>B[p2]) tim[x][i]=A[p1++];
else tim[x][i]=B[p2++];
}
}
int cnt[MAXK+5];
void solve(){
for(int i=1;i<=k;i++) calc(i);
for(int i=1;i<=k;i++) mergesort(i);
for(int i=(inv[0]=inv[1]=1)+1;i<=MAXW;i++)
inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
int sm=0;for(int i=1;i<=k;i++) sm+=w[i];
bool flg=1;
for(int i=1;i<=k;i++) flg&=(tim[i][1]==INF);
if(flg) return puts("-1"),void();
int res=1,cnt0=k,ans=0;
for(int i=1;i<=sm;i++){
int x=0;
for(int j=1;j<=k;j++) if(tim[j][cnt[j]+1]>tim[x][cnt[x]+1]) x=j;
if(!cnt[x]) cnt0--;
else res=1ll*res*inv[cnt[x]]%MOD*(cnt[x]+1)%MOD;
++cnt[x];
if(!cnt0&&tim[x][cnt[x]]) ans=(ans+tim[x][cnt[x]]%MOD*res%MOD*inv[cnt[x]])%MOD;
} printf("%d\n",ans);
}
}
namespace sub2{
int x[MAXK+2],y[MAXK+2],t[MAXK+2];
int mn[MAXK+2][MAXN+5],mx[MAXK+2][MAXN+5],sum[MAXK+2][MAXN+5];
void calc(int r){
for(int i=1;i<=n;i++) if(c[i]==r) t[r]+=d[i];
if(t[r]<0){
t[r]=-t[r];
for(int i=1;i<=n;i++) if(c[i]==r) d[i]=-d[i];
} int cur=0;
for(int i=1;i<=n;i++){
if(c[i]==r) cur+=d[i];sum[r][i]=cur;
mn[r][i]=min(mn[r][i-1],cur);
mx[r][i]=max(mx[r][i-1],cur);
} x[r]=mn[r][n];y[r]=mx[r][n];
}
struct itvl{
ll l,r;
itvl(ll _l=0,ll _r=0):l(_l),r(_r){}
itvl operator &(const itvl &rhs){
return itvl(max(l,rhs.l),min(r,rhs.r));
}
};
int calc(int mid,int id){
static itvl it[MAXK+2];
for(int i=1;i<=k;i++) it[i]=itvl(-x[i]+1,w[i]);
for(int i=1;i<=k;i++){
it[i]=it[i]&itvl(1-1ll*(mid-2)*t[i]-y[i],w[i]-1ll*(mid-2)*t[i]-y[i]);
it[i]=it[i]&itvl(1-1ll*(mid-1)*t[i]-mx[i][id-1],w[i]-1ll*(mid-1)*t[i]-mx[i][id-1]);
} it[c[id]]=it[c[id]]&itvl(w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id],w[c[id]]+1-1ll*(mid-1)*t[c[id]]-sum[c[id]][id]);
int res=1;
for(int i=1;i<=k;i++){
if(it[i].l>it[i].r) return 0;
res=1ll*res*(it[i].r-it[i].l+1)%MOD;
} return res;
}
int ff[15],ifac[15],pre[15],suf[15];
void solve(){
for(int i=(ifac[0]=ifac[1]=1)+1;i<=k+3;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=k+3;i++) ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
for(int i=1;i<=k;i++) calc(i);
bool flg=1;
for(int i=1;i<=k;i++) flg&=(!t[i]&&y[i]-x[i]+1<=w[i]);
if(flg) return puts("-1"),void();
int res=0;
for(int i=1;i<=n;i++) if(d[i]==1){
if(!calc(2,i)) continue;
int p=1e9+1;
for(int j=1;j<=k;j++){
if(t[j]){
chkmin(p,(w[j]+2*t[j]-y[j]+x[j]-1)/t[j]);
chkmin(p,(w[j]+t[j]-mx[j][i-1]+x[j]-1)/t[j]);
}
}
// while(l<=r){
// int mid=l+r>>1;
// if(calc(mid,i)) p=mid,l=mid+1;
// else r=mid-1;
// }
for(int j=2;j<=min(p,k+3);j++){
ff[j]=1ll*calc(j,i)*(1ll*(j-1)*n%MOD+i)%MOD;
ff[j]=(ff[j-1]+ff[j])%MOD;
} if(p<=k+3) res=(res+ff[p])%MOD;
else{
pre[1]=suf[k+4]=1;
for(int j=2;j<=k+3;j++) pre[j]=1ll*pre[j-1]*(p-j+MOD)%MOD;
for(int j=k+3;j>>1;j--) suf[j]=1ll*suf[j+1]*(p-j+MOD)%MOD;
for(int j=2;j<=k+3;j++){
int mul=1ll*pre[j-1]*suf[j+1]%MOD;
mul=1ll*mul*ifac[j-2]%MOD*ifac[k+3-j]%MOD;
if((k+3-j)&1) mul=MOD-mul;
res=(res+1ll*mul*ff[j])%MOD;
}
}
}
for(int i=1;i<=n;i++){
static itvl it[MAXK+2];
for(int j=1;j<=k;j++) it[j]=itvl(1,w[j]);
for(int j=1;j<=k;j++){
it[j]=it[j]&itvl(1-mn[j][i-1],w[j]-mn[j][i-1]);
it[j]=it[j]&itvl(1-mx[j][i-1],w[j]-mx[j][i-1]);
} if(!~d[i]) it[c[i]]=it[c[i]]&itvl(0-sum[c[i]][i],0-sum[c[i]][i]);
else it[c[i]]=it[c[i]]&itvl(w[c[i]]+1-sum[c[i]][i],w[c[i]]+1-sum[c[i]][i]);
int mul=i;
for(int j=1;j<=k;j++){
if(it[j].l>it[j].r) mul=0;
else mul=1ll*mul*(it[j].r-it[j].l+1)%MOD;
} res=(res+mul)%MOD;
}
printf("%d\n",res);
}
}
int main(){
// freopen("walk4.in","r",stdin);
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]);
if(sub1::check()) sub1::solve();
else sub2::solve();
return 0;
}

啊啊啊啊啊啊啊我的 E 队怎么就没了呢

洛谷 P7116 - [NOIP2020] 微信步数(拉格朗日插值)的更多相关文章

  1. [洛谷P4781]【模板】拉格朗日插值

    题目大意:给你$n(n\leqslant2000)$个点,要你求$n-1$次经过这$n$个点的多项式在$k$处的值 题解:$Lagrange$插值:$$f_x=\sum\limits_{i=1}^ky ...

  2. 洛谷P4781 【模板】拉格朗日插值(拉格朗日插值)

    题意 题目链接 Sol 记得NJU有个特别强的ACM队叫拉格朗,总感觉少了什么.. 不说了直接扔公式 \[f(x) = \sum_{i = 1}^n y_i \prod_{j \not = i} \f ...

  3. 【洛谷5437】【XR-2】约定(拉格朗日插值)

    [洛谷5437][XR-2]约定(拉格朗日插值) 题面 洛谷 题解 首先发现每条边除了边权之外都是等价的,所以可以考虑每一条边的出现次数. 显然钦定一条边之后构成生成树的方案数是\(2*n^{n-3} ...

  4. 洛谷 P5469 - [NOI2019] 机器人(区间 dp+拉格朗日插值)

    洛谷题面传送门 神仙题,放在 D1T2 可能略难了一点( 首先显然对于 P 型机器人而言,将它放在 \(i\) 之后它会走到左边第一个严格 \(>a_i\) 的位置,对于 Q 型机器人而言,将它 ...

  5. 洛谷P5437/5442 约定(概率期望,拉格朗日插值,自然数幂)

    题目大意:$n$ 个点的完全图,点 $i$ 和点 $j$ 的边权为 $(i+j)^k$.随机一个生成树,问这个生成树边权和的期望对 $998244353$ 取模的值. 对于P5437:$1\le n\ ...

  6. 洛谷 P3270 - [JLOI2016]成绩比较(容斥原理+组合数学+拉格朗日插值)

    题面传送门 考虑容斥.我们记 \(a_i\) 为钦定 \(i\) 个人被 B 神碾压的方案数,如果我们已经求出了 \(a_i\) 那么一遍二项式反演即可求出答案,即 \(ans=\sum\limits ...

  7. LOJ 2743(洛谷 4365) 「九省联考 2018」秘密袭击——整体DP+插值思想

    题目:https://loj.ac/problem/2473 https://www.luogu.org/problemnew/show/P4365 参考:https://blog.csdn.net/ ...

  8. 洛谷P5158 【模板】多项式快速插值

    题面 传送门 前置芝士 拉格朗日插值,多项式多点求值 题解 首先根据拉格朗日插值公式我们可以暴力\(O(n^2)\)插出这个多项式,然而这显然是\(gg\)的 那么看看怎么优化,先来看一看拉格朗日插值 ...

  9. 【Luogu4781】【模板】拉格朗日插值

    [Luogu4781][模板]拉格朗日插值 题面 洛谷 题解 套个公式就好 #include<cstdio> #define ll long long #define MOD 998244 ...

随机推荐

  1. 【UE4 C++ 基础知识】<14> 多线程——AsyncTask

    概念 AsyncTask AsyncTask 系统是一套基于线程池的异步任务处理系统.每创建一个AsyncTas,都会被加入到线程池中进行执行 AsyncTask 泛指 FAsyncTask 和 FA ...

  2. 2020BUAA软工提问回顾和个人总结作业

    2020BUAA软工提问回顾和个人总结作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾和个人总结作业 我在 ...

  3. Vue报错 type check failed for prop “xxx“. Expected String with value “xx“,got Number with value ‘xx‘

    vue报错    [Vue warn]: Invalid prop: type check failed for prop "name". Expected String with ...

  4. 所驼门王的宝藏(Tarjan)

    题目描述 在宽广的非洲荒漠中,生活着一群勤劳勇敢的羊驼家族.被族人恭称为"先知"的Alpaca L. Sotomon是这个家族的领袖,外人也称其为"所驼门王". ...

  5. linux tr

    转载:tr命令_Linux tr 命令用法详解:将字符进行替换压缩和删除 (linuxde.net) tr命令 文件过滤分割与合并 tr命令可以对来自标准输入的字符进行替换.压缩和删除.它可以将一组字 ...

  6. cf 11B Jumping Jack(贪心,数学证明一下,,)

    题意: 给一个数X. 起始点为坐标0.第1步跳1格,第2步跳2格,第3步跳3格,.....以此类推. 每次可以向左跳或向右跳. 问最少跳几步可以到坐标X. 思路: 假设X是正数. 最快逼近X的方法是不 ...

  7. hdu 1394 Minimum Inversion Number(线段树or树状数组)

    题意: 给你N个数,N个数是0~N-1的一个全排列. 要求统计它的所有形式的逆序对的最小值.它的所有形式的意思是,不断将数组开头的第一个数放到数组的最后面. 逆序对:i<j且ai>aj 思 ...

  8. LOTO虚拟示波器软件功能演示之——FIR数字滤波

    本文章介绍一下LOTO示波器新出的功能--FIR数字滤波的功能. 在此之前我们先来了解一下带通滤波和带阻滤波.我们都知道每个信号是不同频率不同幅值正弦波的线性叠加,为了方便直接得观察到这种现象,就有了 ...

  9. uni-app APP端隐藏导航栏自定义按钮

    话不多说,上代码 // #ifdef APP-PLUS var webView = this.$mp.page.$getAppWebview(); // 修改buttons webView.setTi ...

  10. sklearn模型保存与加载

    sklearn模型保存与加载 sklearn模型的保存和加载API 线性回归的模型保存加载案例 保存模型 sklearn模型的保存和加载API from sklearn.externals impor ...