魔改森林
魔改森林
https://ac.nowcoder.com/acm/problem/200324
前言:
很久很久以前就看到这个题目.记得这题应该是小乔出的.当时我队友来问我,我跟他讲了一下35分的做法.因为那个时候太菜了,不会容斥原理.
思路:
这题前面1000个数据直接dp即可.
后面1e5,直接组合数预处理+容斥原理即可.
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=1e3+5,P=5;
const int mod=998244353;
typedef long long ll;
ll dp[M][M];
ll f[N],ivf[N];
ll ans[P];
bool mp[M][M];
pair<int,int>a[N];
ll qp(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}return res;
}
ll C(ll a,ll b)
{
return f[a]*ivf[b]%mod*ivf[a-b]%mod;
}
void init()
{
f[0]=1;
for(int i=1;i<=N-5;i++) f[i]=f[i-1]*i%mod;
ivf[N-5]=qp(f[N-5],mod-2);
for(int i=N-6;i>=0;i--) ivf[i]=ivf[i+1]*(i+1)%mod;
}
ll cal(ll a,ll b)
{
return C(a+b,a);
}
int main()
{
init();
int n,m,k,limit=1000;scanf("%d%d%d",&n,&m,&k);n++,m++;
for(int i=1;i<=k;i++)
{
int x,y;scanf("%d%d",&x,&y);
a[i]={n-x+1,y};
}
if(n<=limit&&m<=limit)
{
for(int i=1;i<=k;i++) mp[a[i].first][a[i].second]=true;
dp[0][1]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!mp[i][j]) dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
printf("%lld\n",dp[n][m]);
}
else
{
a[++k]={n,m};sort(a+1,a+1+k);
for(int i=1;i<=k;i++)
{
ans[i]=cal(a[i].first-1,a[i].second-1);
for(int j=1;j<i;j++)
{
if(a[j].first<=a[i].first&&a[j].second<=a[i].second)
{
ans[i]-=ans[j]*cal(a[i].first-a[j].first,a[i].second-a[j].second);
ans[i]=(ans[i]%mod+mod)%mod;
}
}
}printf("%lld\n",ans[k]);
}
return 0;
}lpt的小屋 文章被收录于专栏
我想要一份甜甜的爱情
腾讯公司福利 1157人发布
查看5道真题和解析