T1
f(i)表示不和法数大于i个的数量
$$f(i)=C_n^iC_{m-i*k-1}^{n-1}$$
首先n>m||K*n<m一定不合法
先不考虑<K的情况,那就相当于给m个果子,用n个篮子把他们装起来
用挡板法易知
$$ans=C_{m+n-1}^{n-1}$$
即给m个果子中间再加上n-1个挡板的位置,在选n-1个
那考虑必须放一个的情况,只要预先把m -n,相当于每个篮子先放一个
那考虑不合法数>=i个,只需要预先给i个放K个,那这i个一定不合法
但是不保证其他的合法,也不保证这i个不合法的果子数一定是K+1个
所以要用到容斥
这种我们确定了i个不合法的最低高度,但是同一个状态会被像上图一样,被枚举多次
所以要容斥
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int mod=998244353;
const int N=10000066;
ll mi(ll a,ll ci)
{
ll ans=1;
while(ci)
{
if(ci&1)
ans=ans*a%mod;
a=a*a%mod;
ci>>=1;
}
return ans;
}
ll jie[N],jieni[N];
void chu()
{
jie[0]=1;
for(int i=1;i<N;++i)
jie[i]=jie[i-1]*i%mod;
jieni[N-1]=mi(jie[N-1],mod-2)%mod;
for(int i=N-2;i>=1;--i)
jieni[i]=jieni[i+1]*(ll)(i+1)%mod;
jieni[0]=1;
}
ll n,m,K;
inline ll C(ll n,ll m)
{
if(n<0||m<0)
return 0;
if(n<m)
return 0;
return jie[n]*jieni[m]%mod*jieni[n-m]%mod;
}
int main(){
//freopen("T1.in","r",stdin);
chu();
scanf("%lld%lld%lld",&n,&m,&K);
if(n>m)
{
cout<<0;
return 0;
}
ll ans=0;
for(ll i=0;i<=m;++i)
ans=(ans+C(n,i)*C(m-i*K-1,n-1)%mod*((i&1)?-1:1)+mod)%mod;
cout<<ans%mod;
}
T2
仔细想一想就会发现
一条链上、一个环上只能放一个
如果有多条链、多个环组合在一起,ans还是最长链的长度
那只需要tarjan缩个点,再求个最长链即可
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cmath>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define dd double
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=1000006;
struct son
{
int v,next;
};
struct TTT
{
son a1[N*3];
int first[N*3],e;
void clear()
{
mem(a1,0);mem(first,-1);e=0;
}
void addbian(int u,int v)
{
a1[e].v=v;
a1[e].next=first[u];
first[u]=e++;
}
}h[2];
int n,m;
int dfn[N],low[N],now;
int zhan[N*5],he;
bool flag[N];
int dui[N],con,sun[N];
inline void tarjan(int x)
{
low[x]=dfn[x]=++now;
zhan[++he]=x;flag[x]=1;
int temp;
for(int i=h[0].first[x];i!=-1;i=h[0].a1[i].next)
{
temp=h[0].a1[i].v;
//if(flag[temp])
// continue;
if(dfn[temp]==-1)
{
tarjan(temp);
if(low[x]>low[temp])
low[x]=low[temp];
//low[x]=min(low[x],low[temp]);
}
else
if(flag[temp])
{
if(low[x]>dfn[temp])
low[x]=dfn[temp];
//low[x]=min(low[x],dfn[temp]);
}
}
if(dfn[x]==low[x])
{
++con;
while(1)
{
temp=zhan[he--];
flag[temp]=0;
dui[temp]=con;
++sun[con];
if(temp==x)
break;
}
}
}
void chu()
{
for(int i=1;i<=n;++i)
if(dfn[i]==-1)
tarjan(i);
for(int i=1;i<=n;++i)
{
int temp;
for(int j=h[0].first[i];j!=-1;j=h[0].a1[j].next)
{
temp=h[0].a1[j].v;
if(dui[i]!=dui[temp])
h[1].addbian(dui[i],dui[temp]);
}
}
}
int mx[N];
void dfs(int x)
{
flag[x]=1;
int temp;
mx[x]=sun[x];
for(int i=h[1].first[x];i!=-1;i=h[1].a1[i].next)
{
temp=h[1].a1[i].v;
if(flag[temp])
{
if(mx[x]<sun[x]+mx[temp])
mx[x]=sun[x]+mx[temp];
continue;
}
dfs(temp);
if(mx[x]<sun[x]+mx[temp])
mx[x]=sun[x]+mx[temp];
}
}
int work()
{
mem(flag,0);
for(int i=1;i<=con;++i)
if(!flag[i])
dfs(i);
int ans=0;
for(int i=1;i<=con;++i)
if(ans<mx[i])
ans=mx[i];
return ans;
}
int main(){
//freopen("T2.in","r",stdin);
//freopen("bomb.in","r",stdin);
mem(dfn,-1);
h[0].clear();
h[1].clear();
n=read();m=read();
int tin1,tin2;
for(int i=1;i<=m;++i)
{
tin1=read();tin2=read();
h[0].addbian(tin1,tin2);
}
chu();
/*printf("
");
for(int i=1;i<=n;++i)
printf("%d ",dui[i]);
printf("
");*/
cout<<work();
}
然后T3还不会呢...