首页 > 其他分享 >【ACM组合数学 | 错排公式】写信

【ACM组合数学 | 错排公式】写信

时间:2023-04-17 11:35:47浏览次数:68  
标签:frac cup 写信 sum cap ACM leq int 错排

题目链接:https://ac.nowcoder.com/acm/contest/54484/B

题意很简单,但是数据范围偏大。

错排公式

首先来推导一下错排公式:

\[D(n) = n!\sum_{k=0}^{n}\frac{(-1)^k}{k!} \]

设一个函数:

\[S_i表示一个排列中p_i = i的方案数 \]

那么我们可以知道:

\[D(n) = n! - |\cup_{i=1}^{n}S_i| \]

这个表示所有方案数减去至少有一个位置放对的方案数

现在来考虑一下如何处理后面这个并集,并集往往是不好求的,而交集会好求很多,所以在求并集的时候我们往往采取容斥原理将一个并集转换成诸多交集的加减运算

我们用一个图可以来表示当n = 3的情况:

其中有:

\[|S_1 \cup S_2 \cup S_3| = |S_1| + |S_2| + |S_3| - |S_1 \cap S_2| - |S_1 \cap S_3| - |S_2 \cap S_3| + |S_1 \cap S2 \cap S_3| \]

扩展一下就可以得到下面的柿子:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}(-1)^k\sum_{1\leq i_1 \leq i_2 \leq ... \leq i_k \leq n}|S_{i1}\cap S_{i2} ... \cap S_{ik}| \]

然后有:

\[\sum_{1\leq i_1 \leq i_2 \leq ... \leq i_k \leq n}|S_{i1}\cap S_{i2} ... \cap S_{ik}| = C_{n}^{k}(n-k)! \]

这个表示啥呢,左边这个柿子的含义其实是i1 ~ ik都放对了,其他位置上无所谓的方案数,就等同于在n个位置中选择k个放对,剩下的随便放的方案数。

所以可得下面的柿子:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}(-1)^kC_{n}^{k}(n-k)! \]

然后化简得:

\[|\cup_{i=1}^{n}S_i| = \sum_{k=1}^{n}\frac{(-1)^k n!}{k!} \]

然后代回到一开始的答案表达式中:

\[D(n) = n! - \sum_{k=1}^{n}\frac{(-1)^k n!}{k!} \]

n!提出来,再化简一下得到:

\[D(n) = n! \sum_{k=0}^{n}\frac{(-1)^k}{k!} \]

回到本题

但是有这个柿子依然不好写这题,这题如果是1e7就可以直接O(n)写了,但是这题是1e9的数据范围,可以考虑一下分段打表(一般要求函数可以递推),但是这个表达式好像不是很好打,我们来分析一下。

首先网上有一个比较有名递推式(证明略):

\[D(n) = (n-1)[D(n - 1) + D(n - 2)] \]

这个递推需要用到前两项,也就是说我们需要打两个表,然后才可以做,有点麻烦,但是其实是可以只用一项的。

我看网路上都没有用下面这种方式递推的,我在这里写一下。

我们考虑D(n) -> D(n + 1)这样的转移:

\[D(n) = n! \sum_{k=0}^{n}\frac{(-1)^k}{k!} \]

\[D(n + 1) = (n + 1)! \sum_{k=0}^{n + 1}\frac{(-1)^k}{k!} \newline = (n + 1)![\sum_{k=0}^{n}\frac{(-1)^k}{k!} + \frac{(-1)^{n + 1}}{(n + 1)!}] \newline = (n + 1)!\sum_{k=0}^{n}\frac{(-1)^k}{k!} + (-1)^{n + 1} \newline = (n + 1) \times n!\sum_{k=0}^{n}\frac{(-1)^k}{k!} + (-1)^{n + 1} \newline = (n+1) \times D(n) + (-1)^{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;
}

标签:frac,cup,写信,sum,cap,ACM,leq,int,错排
From: https://www.cnblogs.com/eriktse/p/17325308.html

相关文章

  • pacman使用
    //安装包pacman-Sboost-libs//卸载包pacman-Rsboost-libs//显示包版本pacman-Qboost-libs#Displayversion//显示包安装的文件详细列表pacman-Qlboost-libs#Displayfilelistprovidedbylocalpackage//显示包缺失的文件pacman-Qkboost-libs#Checkthel......
  • 电子科技大学第二十一届ACM程序设计竞赛 决赛游记
    Preface第一次线下组队打ACM比赛,算是次很难忘的经验吧昨天晚上和队友才第一次在食堂见面,然后简单交流了下今天的策略方针等其实大部分时间还是在扯皮,没想到刚好三个key厨组成了一队,早知道队名就叫HellBurnsGreen了然后关于赛前,今天早上还算起的挺早,然后不知道干什么就去学校的......
  • 猫猫军阀和它的小犬_acm大陆的游玩记录
    这里是猫猫军阀和它的小犬(也就是我,liyishui)一起在acm大陆游玩的记录。在我们想一起做的所有事情里,一起去骑行,爬雪山,露营,公益,写代码,为了小猫能攒够毕业学分一起参加数模,一起学习..有一天小猫说想陪我打比赛然后就有了后来:D Day1#牛客小白月赛70,小猫做了abc,我去看了篮球赛......
  • 【动态】ACM练题计划
    有计划也不一定能完成任务,但从2月到4月的这段时间里我发现,没有计划根本没法完成任务……因此我创建了这个练习计划,并且把它挂在博客上面,作为对自己的一种激励。日常训练&学习2022年4月本月重点练习的算法:贪心&搜索这个月末将迎来期中考试,因此重心仍然放在学业上但还是要保......
  • 2012-2013 ACM-ICPC, NEERC, Moscow Subregional Contest题解
    题目链接:2012-2013ACM-ICPC,NEERC,MoscowSubregionalContestC.Cinderella(贪心)思路答案为大于平均值的数的数量代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);......
  • UVa 10112 Myacm Triangles (枚举&计算几何)
    10112-MyacmTrianglesTimelimit:3.000secondshttp://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=101&page=show_problem&problem=1053TherehasbeenconsiderablearcheologicalworkontheancientMyacmculture......
  • 广州大学第十七届ACM大学生程序设计竞赛 L. 因子模仿 - hard version 线段树维护矩阵
    传送门大致思路:  观察发现,茉美香胜利会叠加对手所有状态,茉美香失败会被对手叠加所有状态。我们可以用矩阵[a1,a2,b1,b2]表示两个人的状态(其中a1,a2表示茉美香,b1,b2表示对手)茉美香赢了之后的状态是[a1+b1,a2+b2,b1,b2],茉美香输了之后的状态是[a1,b1,a1+b1,......
  • 【ACM博弈论】SG函数入门(1):从巴什博奕到尼姆游戏
    在我小时候以前做题的时候,遇到博弈题往往都是漫无目的地打表找规律,或者找一些特殊情况但是没有很好的分析方法。其实博弈题是有比较套路的解题方法的,那就是利用SG函数,第一节不会讲到SG函数的具体用法,我们先来博弈入个门,学习一下最基本的博弈类型:Nim游戏。......
  • 【ACM算法竞赛日常训练】DAY10题解与分析【月月给华华出题】【华华给月月出题】| 筛法
    DAY10共2题:月月给华华出题华华给月月出题难度较大。......
  • ACM预备队-大一下学期week(3)集训
    1.饿饿,饭饭2题目链接:饿饿饭饭2-Problem-DaimayuanOnlineJudge1#include<iostream>2usingnamespacestd;34intmain(){5intT;6cin>>T;7while(T--){8intn;9cin>>n;10inta[n];1......