题目分析:

我们可以对每一条边单独计算贡献,这样会发现贡献很好算:

\[ans = \sum_{i=0}^{n-1} w_i \sum_{j=0}^S |j - s_i| \binom{i+j-1}{i-1}\binom{S - j + n - i - 1}{n - i - 1}
\]

这样就可以直接40跑路了

上面假设 \(s_i\) 为 \(a\) 的前缀和。

发现难算的就是第二个求和里面的那些,所以就考虑单独考虑,第一步肯定是化绝对值,化出来就是这个样子的:

\[\sum_{j=0}^S (j - s_i) \binom{i+j-1}{i-1}\binom{S - j + n - i - 1}{n - i - 1} + 2 \times \sum_{j=0}^{s_i} (s_i - j) \binom{i+j-1}{i-1}\binom{S - j + n - i - 1}{n - i - 1}
\]

前后其实本质上是一个东西啦,就选后面的去分析吧。

拆开后就是下面这些:

\[s_i \sum_{j=0}^{s_i}\binom{i+j-1}{i-1}\binom{S - j + n - i - 1}{n - i - 1} - \sum_{j=0}^{s_i} j \times \binom{i+j-1}{i-1}\binom{S - j + n - i - 1}{n - i - 1}
\]

其实这个式子我们是有一种冲动的,就是想把它们化的整齐一点,方便合并同类项,那么关键也就是化一下后面的式子啦。

其实就可以化为:

\[i \times \sum_{j=0}^{s_i} \binom{i+j-1}{i}\binom{S - j + n - i - 1}{n - i - 1}
\]

为了舒服一些,我们设出一个 \(f(n,s,i,k)\),其代表:

\[f(n,s,i,k) = \sum_{j=0}^{k}\binom{i+j-1}{i-1}\binom{s - j + n - i - 1}{n - i - 1}
\]

这样我们就可以很轻松地表示出上面这个式子了,即:

\[\sum_{j=0}^{s_i} \binom{i+j-1}{i}\binom{S - j + n - i - 1}{n - i - 1} = f(n+1,S-1,i-1,s_i+1)
\]

其实就是看看怎么把 \(f\) 那个式子变换成这个式子,剩下就不详细说了,这样我们最后的答案就可以表示为:

\[i \times f(n + 1,S - 1,i+1,S-1) - s_i \times f(n,S,i,S) + 2 \times s_i \times f(n,S,i,s_i) - 2 \times i \times f(n+1,S-1,i+1,s_i-1)
\]

我们可以发现因为 \(i,s_i\) 单调递增,所以如果我们可以快速做到由 \(f(n,s,i,k)\) 得到 \(f(n,s,i+1,k)\) 和 \(f(n,s,i,k+1)\) 就可以用线性的复杂度解决问题

可以根据定义直接得到 \(f(n,s,i,k+1)\),但是剩下的那个就很难弄了。

这个时候就要用的 \(f\) 一个很神仙的组合意义:\(s\) 个相同的小球放到 \(n\) 个不同的盒子里,要求前 \(i\) 个盒子放的小球总数小于等于 \(k\) 的方案数。

这个根据定义是很好理解的,每次就是枚举前 \(i\) 个盒子放多少个然后一个插板法。

这个意义其实换句话来说就是:从左到右第 \(k+1\) 个小球一定放在大于编号 \(i\) 的盒子里。那么此时如果我们枚举第 \(k+1\) 个小球放在哪个盒子里,最后得到的式子就是:

\[f(n,s,i,k) = \sum_{j = i+1}^{n} \binom{j + k - 1}{j-1} \binom{n - j + s - k - 1}{n - j}
\]

这个式子就可以解决 \(i\) 的移动了。

这个式子的具体意义就是:\(k\) 个小球放到前 \(j\) 个盒子里,\(s - k - 1\) 个小球放到剩下的 \(n - j + 1\) 个盒子里,这里主要是要注意第 \(j\) 个盒子我们钦定放了第 \(k+1\) 个球,但不一定仅仅是放了这一个。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e6+5;
const int MOD = 998244353;
int fac[N],inv[N],sum[N],w[N];
inline int read(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int mod(int x){
if(x < 0) return (x%MOD + MOD)%MOD;
else return x % MOD;
}
int binom(int n,int m){
if(n < m || n < 0 || m < 0) return 0;
return mod(fac[n] * mod(inv[m] * inv[n - m]));
}
struct fun{
int n,s,i,k,res;
void init(int _n,int _s,int _i,int _k){
n = _n,s = _s,i = _i,k = _k;res = 0;
for(int j=0; j<=k; j++){
res = mod(res + binom(i + j - 1,i - 1) * binom(s - j + n - i - 1,n - i - 1));
}
}
void movei(int x){
if(x <= i) return;
for(int j=i+1; j<=x; j++){
res = mod(res - binom(j + k - 1,j - 1) * binom(s - k - 1 + n - j,n - j));
}
i = x;
}
void movek(int x){
if(x <= k) return;
for(int j=k+1; j<=x; j++){
res = mod(res + binom(i + j - 1,i - 1) * binom(s - j + n - i - 1,n - i - 1));
}
k = x;
}
}f1,f2,f3,f4;
int power(int a,int b){
int res = 1;
while(b){
if(b & 1) res = mod(res * a);
a = mod(a * a);
b >>= 1;
}
return res;
}
void pre_work(int n){
fac[0] = 1;
for(int i=1; i<=n; i++) fac[i] = mod(fac[i-1] * i);
inv[n] = power(fac[n],MOD-2);
for(int i=n-1; i>=0; i--) inv[i] = mod(inv[i+1] * (i+1));
}
signed main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
pre_work(3000000);
int T = read();
while(T--){
int n = read();
for(int i=1; i<=n; i++){
int a = read();
sum[i] = sum[i-1] + a;
}
for(int i=1; i<n; i++) w[i] = read();
int ans = 0,S = sum[n];
f1.init(n+1,S-1,1,S-1);f2.init(n,S,1,S); //只要保证单调增,初值都没啥问题的
f3.init(n,S,1,0);f4.init(n+1,S-1,1,-1);
for(int i=1; i<n; i++){
// printf("%lld %lld %lld %lld\n",f1.res,f2.res,f3.res,f4.res);
int tmp = 0;
f1.movei(i+1);f2.movei(i);f3.movei(i);f3.movek(sum[i]);
f4.movei(i+1);f4.movek(sum[i] - 1);
tmp = mod(tmp + i * f1.res);
tmp = mod(tmp - sum[i] * f2.res);
tmp = mod(tmp + 2 * sum[i] * f3.res);
tmp = mod(tmp - 2 * i * f4.res);
ans = mod(ans + w[i] * tmp);
}
printf("%lld\n",ans);
}
return 0;
}

也可能是我的取模过于离谱,这个题竟然有点卡常。

【题解】[LNOI2022] 盒的更多相关文章

  1. [LNOI2022]盒

    \(LNOI2022\)盒 由于是加的形式,那么可以套路的拆贡献,枚举每条边的贡献就好了 \(40pts\) //比较显然的事情 //首先确定了一个B数组之后 //最小的移动应该是 //设左右两侧比原 ...

  2. 题解 [BZOJ4368][IOI2015]boxes纪念品盒

    题面 解析 可以发现,发纪念品有三种方式: 从左边走再原路返回. 从右边走再原路返回. 走一圈. 注意到,第三种走法最多只会走一次, 因为如果走了多次,那发放的物品数量就会>=\(2k\), 那 ...

  3. 二模Day2题解

    小明搬家 题目描述 小明要搬家了,大家都来帮忙. 小明现在住在第N楼,总共K个人要把X个大箱子搬上N楼. 最开始X个箱子都在1楼,但是经过一段混乱的搬运已经乱掉了.最后大家发现这样混乱地搬运过程效率太 ...

  4. 2018.11.26 QLU新生赛部分题解

    问题 L: 寄蒜几盒? 题目描述 现在有一个圆圈,圆圈上有若干个点,请判断能否在若干个点中选择三个点两两相连组成一个等边三角形? 这若干个点在圆圈上按顺时针顺序分布. 如果可以的话输出"Ye ...

  5. openjudge666:放苹果—题解

    (测试这里的markdown,同时也有纪念意义吧--第一次写的题解) 当时刚学递推的时候做的一道题 oj上的666题 666:放苹果 总时间限制: 1000ms 内存限制: 65536kB 描述 把M ...

  6. 【KMP】洛谷P2375 [NOI2014]动物园 题解

        一开始的方向应该对了,但是没有想到合理的优化还是没写出来…… 题目描述 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己 ...

  7. 洛谷 题解 P1287 【盒子与球】

    题解:P1287 盒子与球 不了解的:stirling数(斯特林数) - 百度百科 分析如下: 设有n个不同的球,分别用b1,b2,--bn表示.从中取出一个球bn,bn的放法有以下两种: 1) bn ...

  8. IOI2015 boxes纪念品盒

    BZOJ 4368: [IOI2015]boxes纪念品盒 BZOJ传送门 Description IOI2015开幕式正在进行最后一个环节.按计划在开幕式期间,每个代表队都将收到由主办方发放的一个装 ...

  9. [bzoj4368][IOI2015]boxes纪念品盒_动态规划_单调队列_贪心

    bzoj4368 IOI2015 boxes纪念品盒 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4368 数据范围:略. 题解: 如果在一个最 ...

  10. css_02之盒模型、渐变

    1.框模型:盒模型,①对象实际宽度=左右外边距+左右边框+左右内边距 + width:②对象实际高度=上下外边距+上下边框+上下内边距 + height: 2.外边距:margin:取值:①top(上 ...

随机推荐

  1. DQL-limit分页

    DQL-limit分页 在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能-limit. 一.limit概述 Limit是 ...

  2. 「浙江理工大学ACM入队200题系列」问题 E: 零基础学C/C++78——求奇数的乘积

    本题是浙江理工大学ACM入队200题第八套中的E题 我们先来看一下这题的题面. 题面 输入 输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你 ...

  3. Java多线程的几种创建方式

    方法一:继承Thread类,重写run方法,直接调用start方法开启线程. /** * 继承Thread类,直接调用start方法开启线程. * @author LuRenJia */ public ...

  4. SpringBoot使用poi实现导出excel

    //实体类 //导出的数据的实体 public class User { private String id; private String name; private String year; // ...

  5. gRPC(Java) keepAlive机制研究

    基于java gRPC 1.24.2 分析 结论 gRPC keepAlive是grpc框架在应用层面连接保活的一种措施.即当grpc连接上没有业务数据时,是否发送pingpong,以保持连接活跃性, ...

  6. 黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论 _

    目录 黏包现象 二.struct模块及解决黏包问题的流程 三.粘包代码实战 UDP协议(了解) 并发编程理论 多道技术 进程理论 进程的并行与并发 进程的三状态 黏包现象 什么是粘包 1.服务端连续执 ...

  7. 函数调用时用const保护指针

    当调用函数并且把指向变量的指针作为参数传入时,通常会假设函数将修改变量(否则,为什么函数需要指针呢?).例如,如果在程序中看到语句 f(&x); 大概是希望f改变x的值.但是,f仅需检查x的值 ...

  8. SAP程序发布流程

    更改程序名称 如果你想要更改程序名称的话,首先进入程序,关闭编辑,只显示代码 点击重命名就可以了 或者直接输入事务代码se38进入APAP编辑器,输入程序名称,重命名 为程序创建事务代码 事务代码为s ...

  9. ChatGPT 可以联网了!浏览器插件下载

    Twitter 用户 An Qu 开发了一款新的 Chrome 插件帮助 ChatGPT 上网,安装插件以后 ChatGPT 就可以联!网!了! 简单来说开启插件后,他可以从网上搜索信息,并且根据用户 ...

  10. Java手写一个批量获取数据工具类

    1. 背景 偶尔会在公司的项目里看到这样的代码 List<Info> infoList = new ArrayList<Info>(); if (infoidList.size ...