Regional Contest H Hopscotch 复现 题解

ACM-ICPC 2017 Mid-Central Regional H Hopscotch题解

题目

原题
原题链接

题意

  • 给定终点(N,N),X轴,Y轴步距:x,y,要想向X轴或者Y轴移动,每次移动距离必须至少等于对应的步距才行。要求输出有多少种移动方式,但是题目同时说明,这个数字可能很大,所以要求我们在计算过程中mod(1e9+7),输出结果时也需要模。

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7,maxn=1e6+7;
ll fac[maxn],niyuan[maxn];
long long qpowmod (long long a,long long b,long long mod){
long long result=1;
while (b){
    if (b&1)
        result=(result*a)%mod;
    b>>=1;
    a=(a*a)%mod;
}
return (result)%mod;
}
ll inv (ll a,ll mod){
    return qpowmod(a, mod-2, mod);
}
ll initial (ll fac[],ll niyuan[]){
    fac[0]=1;
    for (int i=1;i<maxn;i++){
        fac[i]=(fac[i-1]*i)%mod;
    }
    niyuan[maxn-1]=inv(fac[maxn-1], mod);
    for (int i=maxn-2;i>=0;i--){
        niyuan[i]=(niyuan[i+1]*(i+1))%mod;
    }
    return 0;
}

ll C (ll n,ll m,ll fac[],ll niyuan[]){
    if (n>=m)
        return fac[n]*niyuan[m]%mod*niyuan[n-m]%mod;
    else return 0;
}

int main()
{
    ll n,x,y;
    cin>>n>>x>>y;
    ll total=min(n/x,n/y),count=0;
    initial(fac, niyuan);
    for (ll i=0;i<=total;i++){
        count=(count+C(n-i*(x-1)-1,i-1,fac,niyuan)%mod*C(n-i*(y-1)-1,i-1,fac,niyuan)%mod)%mod;
    }
    cout<<count<<endl;
    return 0;
}

思路

  • 这题类似于以前的求有多少种分配方式,不过以前是只有一个需要求,而这里有两个,一个x,一个y,这两种方式对应的方法数求出来之后,将两个数相乘即为此时的总方法数,但是每次至少移动一个x或者y,而一次性可以移动N/y或者N/x个x或者y,因为不能超过N,所以必须取这两个值中的最小值。所以我们只需要分类讨论,把一次移动长度从一个x到N个x所有的情况都加在一起,同时在计算过程中按照题目要求取模即可,要求对应的情况,我们需要使用高中学习的组合数。
  • 本题数据量巨大,不取模不行。而且题目也要求取1e9+7的模。所以本题肯定要用到快速幂/积取模。
  • 组合数取模要用到逆元和费马小定理,逆元的概念为:M*(N!%P)=1,M就是N!%P的逆元。
  • 根据费马小定理,求取逆元简单表述(其实是我也不是很懂怎么证明)如下:若m!%p,它的逆元是(m!)(p-2)维基百科上的费马小定理
  • 求解方法:
    C n m C_n^m Cnm%P
  1. 先算出n!%p、m!%p、(n-m)!%p,用fac[i]表示 i!%p 的值
  2. 因为组合数取模是(n!)/(m!(n-m)!)%p,因此需要计算出m!%p、(n-m)!%p的逆元,根据费马小定理,m!%p、(n-m)!%p的逆元分别是(m!)(p-2)、((n-m)!)(p-2)
  3. 快速幂取模求出(m!)(p-2)%p、((n-m)!)(p-2)%p,分别记录下来,假设标为M和NM
  4. 最后求一下(n!)%p * M* NM % p
  • 由以上思路,我们打表,将1-(1e6+7)范围内所有组合数和逆元都算出来(计算中就得取模),在按照以上描述,将取模之后的阶乘算出,再相乘,累加,过程中别忘记取模。

总结

  • 本题对于现在的我来说,算是难题,本体的思路比较清晰,就是要用到组合数取模我不是很会,百度了之后,才有所了解。
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值