【洛谷AT2642】 [ARC076A] Reconciled?

作者:letianJOE

题目传送门


题目描述

すぬけ君养了 N 只狗和 M 只猴。すぬけ君想把这 N+M 只动物排成一列

すぬけ君希望狗与狗不能互相挨着,猴与猴不能互相挨着。

这样的排列方式有多少种?请输出答案对 10^9+7(1000000007) 取模的结果。不过,狗与狗间,猴与猴间相互区别。


数据范围

  • \large 1 \leq N,M \leq 10^5

输入

输入按以下标准:

N M


输出

输出方案数对 10^9+7(100000007) 取模的结果


样例1解释

将每只狗分别记为A,B,将每只猴分别记为C,D,则共有 ACBD,ADBC,BCAD,BDAC,CADB,CBDA,DACB,DBCA 8 种排列方法。


输入输出样例

输入 #1

2 2

输出 #1

8

输入 #2

3 2

输出 #2

12

输入 #3

1 8

输出 #3

0

输入 #4

100000 100000

输出 #4

530123477

输入 #5

2 2

输出 #5

8

输入 #6

3 2

输出 #6

12

输入 #7

1 8

输出 #7

0

输入 #8

100000 100000

输出 #8

530123477

题目大意

排列组合中的排列,狗和狗不能挨在一起,猴和猴不能挨在一起。


思路 

实际上学过高中数学得人都知道就是数学题

首先,分两种情况讨论。

  • 第一种   

\large \boxed{|n-m|>1}   

把猴和狗依次相邻摆放,可是问题来了

最后一个就没地方了

像这样(三猴五狗)

狗 猴 狗 猴 狗 猴 狗

最后剩一只狗,放哪里都不行。

所以特判这种情况,直接输出0

  •  第二种   

\large \boxed{|n-m|\le 1}

再讲第二种情况前,我们先来看一下数字的全排列怎么求 

假设有3个人要排队,没有特殊限制,想排哪里就排哪里,有几种排队方案呢?

那答案就很简单了

1号 2号 3号
1号 3号 2号
2号 1号 3号
2号 3号 1号
3号 2号 1号
3号 1号 2号

直接 3 * 2 * 1就能推出来了,等于 A^3_3 等于 n!,也就是6种

因此推出 n 的全排列为 n!

如果上面你看懂而且掌握了,那么恭喜你已经攻克了这道题最大的难点

我们可以先把 n(狗) 全排列求出。

再把猴塞到狗和狗的缝隙里,猴也各不相同,所以还要求出 m(猴) 的全排列。

最后在把两种情况相乘,就是答案。


但是,还有一个地方需要我们注意,那就是先排狗,还是先排猴是两种不同的情况。

还是分两种情况:

  • 第一种

\large \boxed{|n-m|=1}

这种没什么好说的,多的排前,所以还是两个全排列相乘

  • 第二种

\large \boxed{\left | n-m \right | = 0}

因为无论是狗排前还是猴排前都是成立的,所以答案还需再乘2

经上所述,得出第二种情况的答案为

 \large \boxed{n! \cdot m! \cdot(2)}

最后推出答案为 

\large ans = \begin{cases} n! \cdot m! & |n-m|=1 \\ n! \cdot m! \cdot 2 & |n-m|=0 \\ 0 & |n-m|>1 \\ \end{cases}

最后记得每次计算都要 mod 1000000007

还要开long long,不然会爆 


样例模拟 

模拟样例#1

输入:2 2

①差的绝对值小于1,所以进入第二种情况

②差为0,所以答案为 2! \times 2! \times 2 ,也就是8

③由于小于 1000000007 ,所以不用取模,答案还是8

跟输出一样


代码

经过分析,实际上这一题没那么难,没有绿题的程度

最后上ACcode 

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000007;
long long n,m,ans1=1,ans2=1;
int main()
{
    cin>>n>>m;
    if(abs(n-m)>1) //第一种情况
    {
        cout<<0<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++) //第二种情况
	    ans1=(ans1*i)%maxn;
    for(int i=1;i<=m;i++)
	    ans2=(ans2*i)%maxn;
    if(n-m==0) //如果差0
      	ans1*=2;
    cout<<(ans1*ans2)%maxn;
    return 0;
}

​​​​​​测试记录

我有参加代码公开计划

本人是个 蒟蒻 ,学艺不精。如有错误,请在评论区指出。

觉得这篇博客对你有帮助的话,那就点个赞吧。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值