Codeforces 869C The Intriguing Obsession 组合数取模

这是一场物语场,而且A题直接puts("Karen")能过,我对此印象非常深.我不知道大家记不记得.
我做的时候一看当场就用 php p h p 写了交上去.
好的那我们现在看C题.

Codeforces 869C The Intriguing Obsession

海上有三个区域,每个区分别有a,b,c个岛屿.
火怜和月火现在想要在区与区之间建设桥梁,但是有如下限制.
1:同一个区的两个岛之间不连通或者连通且最短距离不小于3
2:每一座桥的距离假设都为1
问:一共有多少种不同的建桥方法,桥的数量可以是任意的合法的数量。
a,b,c<=5000.最后取模998244353.

思考一下人生.

那么这题看上去像是一个组合数取模题.
实际上它真的是一个组合数取模题.

/*
首先我们来看.同一个区域中的两个点之间绝对不能造桥.
同理如果一个区域中两个点同时连了另一个区域的同一个点也是不行的.
那么根据抽屉原理,两个区域中要想连边,这两个区域中选择的点的数量必须要相同.
那么接下来就是从两个区域中每次找出i个点来,求一下组合C(a,i)*C(b,i).
然后两个区域找出来的i个点之间可以随意相连,连法一共i!种.
所以a,b两个区域之间相连的办法有C(a,i)*C(b,i)*i!种.
再看三个区域之间相连,你会发现只要不进行上面两种操作,不可能会出现不合法的情况.
比如说1->2->3->4,其中1,4在一个区域里,2和3都分别在另一个区域里,1,4的最短路径是3,明显是符合题意的.
那么这样,a与b,b与c,c与a之间的连线都是互不干扰的,可以分别计算.
设a,b之间相连的办法为tc,b,c之间相连的办法为ta,a,c之间相连的办法tb.
则答案就是(1+ta+tb+tc+ta*tb+ta*tc+tb*tc+ta*tb*tc).(不造桥有1种方法.)
数据范围是5000,可以用杨辉三角预处理组合数,也可以用阶乘逆元,这个就看你自己了.
*/
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int mod=998244353,yuzu=1e5;
ll jic[yuzu|10]={1},inv[yuzu|10];

ll kasumi(ll a,ll b=mod-2){
ll s=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) s=s*a%mod;
return s;
}

ll zuhe(int n,int m){
return jic[n]*inv[m]%mod*inv[n-m]%mod;
}

int main(){
int i,j,a=read(),b=read(),c=read();
for (i=1;i<=yuzu;++i) jic[i]=jic[i-1]*i%mod;
inv[yuzu]=kasumi(jic[yuzu]);
for (i=yuzu-1;~i;--i) inv[i]=inv[i+1]*(i+1)%mod;
ll ta=0,tb=0,tc=0;
for (i=1;i<=min(a,b);++i) tc=(tc+zuhe(a,i)*zuhe(b,i)%mod*jic[i]%mod)%mod;
for (i=1;i<=min(a,c);++i) tb=(tb+zuhe(a,i)*zuhe(c,i)%mod*jic[i]%mod)%mod;
for (i=1;i<=min(b,c);++i) ta=(ta+zuhe(b,i)*zuhe(c,i)%mod*jic[i]%mod)%mod;
write(((ta+tb+tc+ta*tb%mod+ta*tc%mod+tb*tc%mod)%mod+ta*tb%mod*tc%mod+1)%mod);
/*这代码后面4行太暴力了.*/
}

谢谢大家.

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值