小圆前辈的暴力枚举(逆元,数学思维题)

题目
分别考虑放 0到min(n,m)个棋子的情况,加起来就是答案。
放一个棋子时 方案数为nm;
放第二个棋子时,可放的格子数减少(n+m-1)个 放在上一个棋子的基础下进行计算,即(n
m-1)(nm-1-(n+m-1)),此时有重复部分,每个方案重复了 2!次(全排列),除以棋子个数的全排列即可,除法不能直接取模,计算逆元即可(除x取模k,相当于乘x关于k的逆元)
我这里用的是拓展欧几里德求逆元。

#include<iostream>
#include<algorithm>
#include<iomanip>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string.h>
#include<string>
#include<math.h>
#define VNAME(value) (#value)
#define debug(x) {cout<<VNAME(x)<<"="<<(x)<<endl;} 
using namespace std;
const int N = 200000;
const int inf=0x3f3f3f3f;
const int mod=998244353;
typedef long long ll;
void ex_gcd(ll a, ll b, ll &x, ll &y, ll &d){
      if (!b) {d = a, x = 1, y = 0;}
      else{
          ex_gcd(b, a % b, y, x, d);
          y -= x * (a / b);
      }
  }
ll inv(ll t, ll p)
{
     ll d, x, y;
     ex_gcd(t, p, x, y, d);
     return d == 1 ? (x % p + p) % p : -1;
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	ll n,m;
	cin>>n>>m;
	ll ans=1;
	ll sum=n*m;
	ll now=n*m;
	ll k=1;
	for(ll i=1;now;i++)
	{
		ans+=sum*inv(k,mod); 
		ans%=mod;
		now-=(n-i+m-i+1); 
		sum*=now;sum%=mod;
		k*=i+1;k%=mod;
	}
	cout<<ans%mod<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值