【YBT2023寒假Day3 B】你的名字(数学)(拉格朗日插值)

你的名字

题目链接:YBT2023寒假Day3 B

题目大意

问你一个 n*m 的表格里,你选择行列都互不相同的三个点,费用是三个点的两两曼哈顿路径之和。
问你有多少选法的费用在 L~R 之间。

思路

首先变成求 1R
接着思考一下会发现答案是这个:
max(x1,x2,x3)min(x1,x2,x3)+max(y1,y2,y3)min(y1,y2,y3)

然后你考虑枚举 x 那边的值,然后再枚举 y 那边的值,然后在 2x<n,2y<m,i+jR/2 的情况下,考虑统计它的方案。
那首先是最大值(或者最小值)放的方案,然后是中间那个放的方案,然后是点的排名:
3!(ni)(i1)3!(mj)(j1)
不过点之间是一样的,所以要除一个 3!

不难想象我们可以预处理 (mj)(j1) 的前缀和,设其为 S(j),然后枚举 i 来做到 O(n)
考虑如何继续优化,由于随着 i 增大 j 的可选区间变化可能是一个先不变再变小,我们进行分类讨论。

如果 R/2m+1,那 R/2im1,那 (ni)(i1)S(min(m1,R/2i))
那这个是关于 i 5 次多项式(S() 里面是三次),那前缀和就是 6 次多项式。

如果 m+1<R/2n+m2,那你可以分成两段:3!(i=2R/2m+1(ni)(i1)S(m1)+i=R/2m+2min(n1,R/22)(ni)(i1)S(R/2i))
那前面的提取出 S(m1) 就两个前缀和相乘。
后面那一段你先也弄成两个前缀和相减变成 1x 的形式,然后就也是 6 次多项式。

那对于这些 6 次多项式,其实我们可以轻松的求出 17 的时候他们的值,那用这些值拉格朗日差值一下就好了。

代码

#include<cstdio> #include<iostream> #define ll long long #define mo 1000000007 using namespace std; ll n, m, L, R, inv2, inv6, jc[11]; ll ksm(ll x, ll y) { ll re = 1; x %= mo; while (y) { if (y & 1) re = re * x % mo; x = x * x % mo; y >>= 1; } return re; } ll sum1(ll now) { now %= mo; return now * (now + 1) % mo * inv2 % mo; } ll sum2(ll now) { now %= mo; return now * (now + 1) % mo * (2 * now + 1) % mo * inv6 % mo; } ll S(ll R, ll n) { ll re = n % mo * (sum1(R) - R % mo + mo) % mo; (re += mo - sum2(R) + sum1(R)) %= mo; return re; } ll tmp[11]; ll la(ll R, ll k) { if (k < 1) return 0; for (int i = 1; i <= 7; i++) tmp[i] = (tmp[i - 1] + (n % mo - i + mo) % mo * (i - 1) % mo * S(R - i, m) % mo) % mo; if (k <= 7) return tmp[k]; ll re = 0; for (int i = 1; i <= 7; i++) { ll sum = 1; for (int j = 1; j <= 7; j++) if (j != i) sum = sum * (i - j + mo) % mo; (re += tmp[i] * ksm(k - i, mo - 2) % mo * ksm(sum, mo - 2) % mo) %= mo; } for (int i = 1; i <= 7; i++) re = re * ((k - i) % mo) % mo; return re; } ll slove(ll R) { R = min(R / 2, n + m - 2); if (R <= m + 1) return la(R, min(R - 2, n - 1)); else { ll re = S(m - 1, m) * S(R - m + 1, n) % mo; (re += la(R, min(n - 1, R - 2))) %= mo; (re += mo - la(R, R - m + 1)) %= mo; return re; } } int main() { freopen("table.in", "r", stdin); freopen("table.out", "w", stdout); jc[0] = 1; for (int i = 1; i <= 10; i++) jc[i] = jc[i - 1] * i % mo; inv2 = ksm(2, mo - 2); inv6 = ksm(6, mo - 2); scanf("%lld %lld %lld %lld", &n, &m, &L, &R); printf("%lld", (slove(R) - slove(L - 1) + mo) % mo * 6 % mo); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day3_B.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示