The 2018 ACM-ICPC China JiangSu Provincial Programming Contest快速幂取模及求逆元

本文介绍了一种基于排列组合原理的游戏关系管理算法,该算法用于计算玩家如何与游戏中的多个角色建立满额关系的方法数量。通过预处理逆元和阶乘,实现高效计算,解决了ACM-ICPC江苏省级竞赛中的一道题目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目来源

The 2018 ACM-ICPC China JiangSu Provincial Programming Contest

35.4%

  • 1000ms
  • 65536K

Persona5 is a famous video game.

In the game, you are going to build relationship with your friends.

You have N friends and each friends have his upper bound of relationship with you. Let's consider the ithi^{th}ith friend has the upper bound UiU_iUi. At the beginning, the relationship with others are zero. In the game, each day you can select one person and increase the relationship with him by one. Notice that you can't select the person whose relationship with you has already reach its upper bound. If your relationship with others all reach the upper bound, the game ends.

It's obvious that the game will end at a fixed day regardless your everyday choices. Please calculate how many kinds of ways to end the game. Two ways are said to be different if and only if there exists one day you select the different friend in the two ways.

As the answer may be very large, you should output the answer mod 1000000007

Input Format

The input file contains several test cases, each of them as described below.

  • The first line of the input contains one integers N(1≤N≤1000000)(1 \le N \le 1000000)(1N1000000), giving the number of friends you have.
  • The second line contains NNN integers. The ithi^{th}ith integer represents UiU_iUi(1≤Ui≤1000000)( 1 \le U_i \le 1000000)(1Ui1000000), which means the upper bound with ithi^{th}ith friend. It's guarantee that the sum of UiU_iUi is no more than 1000000.

There are no more than 10 test cases.

Output Format

One line per case, an integer indicates the answer mod 1000000007.

样例输入
3
1 1 1
3
1 2 3
样例输出
6
60
题目大意:有n个朋友,开始和每个朋友的关系为0,给出每个朋友的关系上限,每天只能和一个朋友的关系度增加1,求有多少种方式能够和他们的关系都达到上限。
解题思路:这道题很明显就是高中数学里面的排列组合题,我们可以先忽略先后顺序,直接把每个关系度看成一个朋友然后去掉是同一朋友的关系度,本质就是多重集合的排列计数问题 令 sum=a(1)+a(2)+。。。+a(n) ,答案就是 sum!/a1!a2!...an! 需要先打表,预处理逆元跟阶乘,否则会超时 复杂度:O(nlogn)(预处理)
附上AC代码:
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=1e6+1;
 5 const int mod=1e9+7;
 6 ll fac[maxn],facinv[maxn];
 7 ll n,a[maxn];
 8 
 9 ll qpow(ll a,ll b,ll p)  //快速幂取模
10 {
11     ll res=1;
12     while(b)
13     {
14         if(b&1) res=res*a%p;
15         b>>=1;
16         a=a*a%p;
17     }
18     return res;
19 }
20 
21 void init()  //求出阶乘与逆元
22 {
23     fac[0]=fac[1]=facinv[0]=facinv[1]=1;
24     for(int i=2;i<maxn;i++)
25     {
26         fac[i]=fac[i-1]*i%mod;
27         facinv[i]=facinv[i-1]*qpow(i,mod-2,mod)%mod;
28     }
29 }
30 
31 int main()
32 {
33     init();
34     while(cin>>n)
35     {
36         ll sum=0;
37         ll ans=1;
38         for(int i=1;i<=n;i++)
39         {
40             scanf("%d",&a[i]);
41             sum+=a[i];
42             ans=ans*facinv[a[i]]%mod;
43         }
44         ans=ans*fac[sum]%mod;
45         printf("%d\n",ans);
46     }
47     return 0;
48 }

 求逆元参考博客:https://blog.youkuaiyun.com/baidu_35643793/article/details/75268911

转载于:https://www.cnblogs.com/zjl192628928/p/9383166.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值