【题目背景】c++
墙角那株海棠,是你种下的思念。测试
生死不能忘,高烛照容颜。spa
一曲江城唱晚,重忆当年坐灯前,3d
青衫中绣着你留下的线。code
——银临《江城唱晚》blog
【问题描述】get
扶苏是个喜欢一边听古风歌一边写数学题的人,因此这道题实际上是五三原题。数学
歌曲中的主人公看着墙边的海棠花,想起当年他其实和本身沿着墙边种了一排海 棠,可是现在都已枯萎,只剩下那一株,寄托着对他深深的思念。it
沿着墙一共有 n 个位置能够种下海棠花,主人公记得本身当年和他一共种下了 m 朵,因为花的特性,海棠不能紧挨着种植,也就是两朵海棠花之间最少间隔一个不种花 的空位置。可是她记不清当时海棠花具体是怎么摆放的了,因此她想知道一共有多少方 案使得 m 朵海棠花都被种下且两两之间不是相邻的。咱们将这 m 朵海棠花按照 1,2,3…m 的顺序编号,两个种花的方案不一样当且仅当它们被种下的位置不一样或者从左向 右数花的编号序列不一样。io
为了不输出过大,答案对一个参数 p 取模
【输入格式】
输入文件名为 ilove.in。
输入文件中有且仅有一组数据,只有一行四个数字,分别表明 type,n,m,p。其中 type 是一个帮助你判断测试点类型的参数,会在数据范围中说明。
【输出格式】
输出文件名为 ilove.out。
输出一行一个数字,表明答案对 p 取模的结果。
【输入输出样例 】
【数据规模与约定】
而后这套题的最后有句话:
(我恨了)
好了下面来讲正解
SOLUTION:
首先,这是一道五三上的原题,因此它必定能够用数学的方法来计算。
其实这是一道zhx问题,但当你找不到思路时,不妨在考场上打打表找规律
若是关心排列顺序的话,每一个n与m的组合彷佛都对应一个排列数呢qwq
n=8,m=3对应排列数:C63,n=7,m=3对应排列数:C53
而样例对应的C22,再仔细观察,不难推测对应的排列数与n和m的取值有关,因而咱们大胆假设,在不考虑排列顺序的前提下,这m盆花摆在n个位置的方案数是Cn-m+1m(好啦数学证实一下)
(对于任意两盆海棠花,不能够相邻的种植,那么每盆海棠花至关于占据了两个位置,由于会有一盆并不须要占据,例如对于三盆花,须要占据五个位置,因此咱们用n-m+1,直接删去必定不能占的位置,或者咱们能够感性的理解成:先将这m盆花放到n-m+1个位置中(不考虑空隙),若是两盆花相邻了,就加一个空位在这两盆花中间。那么方案数就是将m盆花摆放在n-m+1个空位中的方案数)
求出了全部组合方案后,对于每种方案,都有Amm种不一样的排列方法,因此最后答案就是:
Cn-m+1m*Amm
可是问题来了,看数据范围:
这可了不起了,这怎么算啊;
其实上面的式子能够展开再化简:
Cn-m+1m=(n-m+1)! /m!*(n-2m+1)!
Amm=m!;
Cn-m+1m*Amm=(n-m+1)!/(n-2m+1)!
=(n-m+1)*(n-m)*……*(n-2m+2);
因此这样就能够用很短的代码直接for循环出来啦:
#include<bits/stdc++.h> using namespace std; inline long long read(){ long long ans=0; char last=' ',ch=getchar(); while(ch<'0'||ch>'9') last=ch,ch=getchar(); while(ch<='9'&&ch>='0') ans=ans*10+ch-'0',ch=getchar(); if(last=='-') ans=-ans; return ans; } long long type,n,m,p; int main(){ type=read();n=read();m=read();p=read(); long long ans=1; for(int i=n-2*m+2;i<=n-m+1;i++) ans=(ans*i)%p; printf("%d",ans%p); return 0; }
毕竟zay写了题解,因此咱们放一下:
end-