- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
题目链接: https://ac.nowcoder.com/acm/contest/54484/B 。
题意很简单,但是数据范围偏大.
首先来推导一下错排公式:
设一个函数:
那么我们可以知道:
这个表示 所有方案数 减去 至少有一个位置放对的方案数 .
现在来考虑一下如何处理后面这个并集,并集往往是不好求的,而 交集会好求很多 ,所以在求并集的时候我们往往采取容斥原理将一个并集 转换成诸多交集的加减运算 .
我们用一个图可以来表示当 n = 3 的情况:
其中有:
扩展一下就可以得到下面的柿子:
然后有:
这个表示啥呢,左边这个柿子的含义其实是 i1 ~ ik 都放对了,其他位置上无所谓的方案数,就等同于在 n 个位置中选择 k 个放对,剩下的随便放的方案数.
所以可得下面的柿子:
然后化简得:
然后代回到一开始的答案表达式中:
把 n! 提出来,再化简一下得到:
但是有这个柿子依然不好写这题,这题如果是 1e7 就可以直接O(n)写了,但是这题是 1e9 的数据范围,可以考虑一下分段打表(一般 要求函数可以递推 ),但是这个表达式好像不是很好打,我们来分析一下.
首先网上有一个比较有名递推式(证明略):
这个递推需要用到前两项,也就是说我们需要打两个表,然后才可以做,有点麻烦,但是其实是可以只用一项的.
我看网路上都没有用下面这种方式递推的,我在这里写一下.
我们考虑 D(n) -> D(n + 1) 这样的转移:
然后令段大小 T = 1e7 打表打出 D(0), D(T), D(2T) ... D(100T) 就好了.
最终的复杂度是 O(n) 但是常数极小,所以可以过.
Code
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int p = 1e9 + 7, T = 1e7;
int a[110] =
{
1,824182295,933713113,474482547,930651136,251064654,637937211,229643390,307311871,448853213,
322273426,398890147,194914852,884947442,154199209,881788023,389699639,733217502,601739182,
372305477,213823357,713959988,498202615,196342945,324300550,154001751,974475946,540773759,
467881322,257531902,598680559,367927849,971346692,94577421,617165552,128327758,503709458,
253566817,820144401,13965056,82358069,805941568,533047638,69430220,686678173,297170813,
34546238,323435423,499126069,487532712,468899710,790590914,581347156,955359050,700529992,
518280890,98592091,64544225,988209678,422603955,40661679,174468756,573631136,757555557,
710709955,775098981,499158883,969149294,880429710,42564126,333697951,522067888,579797877,
528967798,717694718,309384913,31308092,316850320,220854491,878646494,963974981,377654637,
705101053,542246848,466289530,750036412,819636314,688721174,464087273,517164631,256789690,
482685016,276682441,473333947,340221393,762927538,624766601,984537252,977632075,34192646,
402182971,977005016
};
int mo(int x){return (x % p + p) % p;}
void solve()
{
int n;cin >> n;
int ans = a[n / T];
for(int i = n / T * T + 1;i <= n; ++ i)ans = mo(ans * i % p + ((i & 1) ? -1 : 1));
cout << ans << '\n';
}
void table()
{
int x = 1;//d(0) = 1,这个有点特殊
cout << x << ",";
int cnt = 1;
for(int i = 1;i <= 1e9; ++ i)
{
x = x * i % p;
if(i & 1)x = (x - 1 + p) % p;
else x = (x + 1) % p;
if(i % T == 0)
{
cout << x << ",";
cnt ++;
}
if(cnt % 10 == 0)
{
cout << '\n';
cnt = 1;
}
}
}
signed main()
{
table();
solve();
//return 0;
}
最后此篇关于【ACM组合数学|错排公式】写信的文章就讲到这里了,如果你想了解更多关于【ACM组合数学|错排公式】写信的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我对为什么我的 Excel 工作簿中的 if 公式不起作用感到目瞪口呆。 像 =if(F2=0, TRUE, FALSE) 这样简单的事情会引发一般错误“这个公式有问题”。不知道在哪里可以解决这个问题
在链接的电子表格中,我试图总结从一月到单元格 B1 中的日期的列 R 类别的所有实例(对于这个例子,让我们说“CAM 收入”)。 在这种情况下,总和应该是 ( B7:F7 ) 和 ( B9:F9 )
这是一个两部分的问题。我想根据价格的生效日期查找商品的价格。我看过垂直生效日期的例子,但我的有点不同。我在第一列 (A) 中有项目。其余列包含带有价格生效日期的标题。希望我能够附上格式示例。我以这种方
我想从第一个单元格开始自动增加月份。 A1 = 2019-01 以下单元格中的公式应自动填充其余单元格。 A2 = 2019-02 : : A13 = 2020-01 有没有一种简单的方法可以做到这一
在 Excel 中,如果 2021 年是基准年(第 1 年),并且我正在以月份为单位进行财务模型(但仍想知道该月份对应于哪一年),我可以使用什么公式来表示月份 0- 12 是第 1 年,第 13-24
我有以下公式,但它不起作用,因为当我在名称周围添加加利福尼亚时它只是失败了,所以它只是告诉我一切都是英国。我怎样才能解决这个问题? =IF(OR(N10776="*California*",N1077
我有这个公式: =IF(AD491="In progress" OR AD491="Reopened"(ROUND($BW$1-AI491,0),($BW$1-BB491+1)) 它正在检查单元格 A
我想做一个总结表。 我创建了一个名称下拉列表:Bob、Jack、Beth 和一个包含两个选项的下拉列表:已完成或更正待定。 在任务旁边的 Sheet2 上,您将选择名称,然后选择两个选项之一。 在摘要
如果我在 A 列中有以下数据: A1 = 3.5.15 A2 = 2.6 A3 = 8.4.3.16.7 我想要一个公式,它可以在下一列 B 中返回以下内容: B1 = 3.5 B2 = 2 B3 =
我在 Excel 2013 中有一张水果表。 我想通过从当前行到顶部搜索直到第一次出现“::”来填充“类别”列,这是表中类别的关键字。 如果有某种方法可以反转范围,我可以执行类似 "=Match(":
我这里有 2 张 table : 我要填写Code表 1 中的列,引用表 2。值的条件是开始日期必须在 ProductionDate 之间。和 ExpiryDate表 2 的类型,表 1 中的类型必须
我有以下工作表: 网格填充有以下公式(此示例来自单元格 H4),该公式根据左侧表格中的输入填充网格,=IF($A4="","",IF(AND($E4="Daily",H$2>=$D4,H$2=$D4,
我在 A1 中有以下值。当我向下拖动时,它应该以如下所示的方式增加。 B 应该首先增加,保持 C 不变。一旦 B 达到最大值,即 2,则 C 应该增加。 C 的最大值实际上取决于行号,行号除以 2 或
我会尽我所能理解这一点。我很讨厌把事情说清楚。 :) 所以……就这样…… 我有一张电子表格,上面列出了我种植辣椒的种子。这是我的专栏,我会在后面解释更多。 裁剪 |颜色 |一代 |物种 |来源 |斯科
我在 Excel 电子表格中有两个列表。 第一个列表有字符串,例如 1234 blue 6 abc xyz blue/white 1234 abc yellow 123 另一个列表包含第一个列表的子字
我正在尝试创建一个 SumIf 公式,该公式根据一个标准将多个列添加在一起。 =sumif(F$8:F$58,F73,L$8:L$58+I$8:I$58) 这给了我一个错误,并且不会将两列加在一起。
你好我想知道是否有一个公式相当于每个语句。 我知道使用 VBA 可以做到这一点,但鉴于这是一份官方报告,我更愿意让它无宏。 基本上我有一个列(假设是 A),其中包含支付发票的时间 ` |------
任何用于计算频率表中数据平均值(众数、标准差、...)的简单 Excel 公式,如下所示: value frequency 5 3 8 5 4 1
例如:您希望在 Z# 年的每年年初以今天的美元收到 $X。假设 3% 的恒定通货膨胀率和 7% 的复合年返回率。 我知道计算通货膨胀调整后 yield 的公式;对于返回率,您必须使用以下公式: [[(
需要一些帮助来找出一个公式来计算一个值在列中列出的次数。我将尝试解释下面的要求。 下图显示了数据集的示例。 要求是列出每个客户的问题和行动。 如您所见,即使从单元格中聚集的值中,我们也需要找出各个唯一
我是一名优秀的程序员,十分优秀!