标签:tor 需要 数组 有序 void getc int 排序 要求
看到数据范围应该都会多多少少有点思路了,要搞一个大概是\(n^3\)的\(dp\),可是貌似最多的方案数是\(200!\)级别的,计算器一算发现是\(6e600+\),于是要套高精。所以之前的\(n^3\)排除,将注意力放在\(n^2-n^2logn\),可\(logn\)这种奇怪的复杂度怎么会无缘无故出现在一个\(n<=200\)的题目?于是果断考虑\(n^2dp\)
\(n^2\)都知道什么意思吧,就是设置两个状态的\(dp\)方程
首先应当想到先排序,因为当身高有序后才能方便找出比某一女生矮的男生有多少,以方便进行\(dp\)计算
考虑设置\(dp\)方程\(f_{i,j}\)表示当前遍历到第\(i\)矮的女生,我们已经匹配了\(j\)对,并且\(j\)对全是女大于男的方案数,这样的话\(dp\)方程可以比较快地得到
考虑将第\(i\)个女生与比第\(i\)个女生矮而不矮于第\(i-1\)个女生的一众男生(设人数为\(p\))一起加入\(f_{i,j}\)的更新
那么\(f_{i,j}\)首先肯定无条件继承\(f_{i-1,j}\)的值,而当\(p>j-1\)时表明我们可以再已经有\(j-1\)对的基础上再扩展一对女大于男的舞伴,并且扩展的这一对有\(p-(j-1)\)种方案,那么\(f_{i,j}\)就需要加上\(f_{i,j-1} * (p-j+1)\)
但是\(f_{n,j}\)还是不能帮我们解决问题,嗯
但已经接近尾声了,考虑设置\(g_j\)表示选完所有对,而其中至少有\(j\)对的方案数,那么显然\(g_j=f_{n,j} * (n-j)!\)(因为剩下\(n-j\)对没有要求,那么就是全排列嘛)
得到了\(g_j\)数组后就很容易想到容斥得到答案了(容斥系数自己可以瞎搞搞出来):
最后一点小注,本篇题解是对该题第一篇题解的一点补充,代码实现思路几乎相同。但由于彼题解有些许瑕疵(也可能是我太蒟蒻)导致没有怎么看懂,后来仔细推敲代码并手搞式子才有了以上这些想法,担心会有和我一样的小菜鸡(应该不会吧)对于首篇的做法有迷惑,于是作此题解来造(bao)福(fu)人(she)类(hui)
代码(代码中的\(f_{i,j}\)是用的滚动数组,没算\(g_j\)而是直接代入\(ans\)公式,若还有不懂欢迎私信):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read()
{
int x=0,f=1;char ch=getchar();
for(;ch<‘0‘||ch>‘9‘;ch=getchar()) f=ch==‘-‘?-1:1;
for(;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
const int xx=2e2+10,xd=100;
const int digit=1e9;
int m[xx],wm[xx],n,k;
struct Big
{
ll a[xd];
inline void print()
{
for(register int i=a[0];i;--i)
{
if(i!=a[0])
for(register int j=1e8;j>=10;j/=10)
a[i]<j?putchar(‘0‘):j=1;
printf("%d",a[i]);
}
puts("");
}
}zero,one,fac[xx],f[2][xx],C[xx][xx];
Big ans;
Big operator * (Big x,Big y)
{
Big tmp=zero;tmp.a[0]=x.a[0]+y.a[0];
for(register int i=1;i<=x.a[0];++i)
for(register int j=1;j<=y.a[0];++j)
{
tmp.a[i+j-1]+=x.a[i]*y.a[j];
if(tmp.a[i+j-1]>=digit)
{
tmp.a[i+j]+=tmp.a[i+j-1]/digit;
tmp.a[i+j-1]%=digit;
}
}
while(!tmp.a[tmp.a[0]]&&tmp.a[0]>1)
--tmp.a[0];
return tmp;
}
Big operator * (int x,Big y)
{
Big tmp=zero;tmp.a[0]=y.a[0]+1;
for(register int i=1;i<=y.a[0];++i)
{
tmp.a[i]+=x*y.a[i];
if(tmp.a[i]>=digit)
{
tmp.a[i+1]+=tmp.a[i]/digit;
tmp.a[i]%=digit;
}
}
while(!tmp.a[tmp.a[0]]&&tmp.a[0]>1)
--tmp.a[0];
return tmp;
}
Big operator + (Big x,Big y)
{
Big tmp=zero;tmp.a[0]=max(x.a[0],y.a[0])+1;
for(register int i=1;i<=tmp.a[0]-1;++i)
{
tmp.a[i]+=(x.a[i]+y.a[i]);
if(tmp.a[i]>=digit)
{
tmp.a[i+1]+=tmp.a[i]/digit;
tmp.a[i]%=digit;
}
}
while(!tmp.a[tmp.a[0]]&&tmp.a[0]>1)
--tmp.a[0];
return tmp;
}
Big operator - (Big x,Big y)
{
Big tmp=zero;tmp.a[0]=x.a[0];
for(register int i=1;i<=x.a[0];++i)
{
tmp.a[i]=x.a[i]-y.a[i];
if(tmp.a[i]<0)
{
tmp.a[i]+=digit;
--x.a[i+1];
}
}
while(!tmp.a[tmp.a[0]]&&tmp.a[0]>1)
--tmp.a[0];
return tmp;
}
inline void pre()
{
memset(zero.a,0,sizeof(zero.a));
zero.a[0]=one.a[0]=one.a[1]=1;
for(register int i=0;i<=n;++i)
C[i][0]=one;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
C[i][j]=C[i-1][j]+C[i-1][j-1];
for(register int i=0;i<=1;++i)
for(register int j=1;j<=n;++j)
f[i][j]=zero;
fac[0]=one;
for(register int i=1;i<=n;++i)
fac[i]=i*fac[i-1];
f[0][0]=f[1][0]=one;
}
int main()
{
n=read(),k=read(),pre();
for(register int i=1;i<=n;++i) m[i]=read();
for(register int i=1;i<=n;++i) wm[i]=read();
sort(m+1,m+n+1),sort(wm+1,wm+n+1);
for(register int i=1,K=0;i<=n;++i)
{
while(K<n&&m[K+1]<wm[i])
++K;
for(register int j=1;j<=i;++j)
{
if(K>j-1)
f[i&1][j]=(K-j+1)*f[(i-1)&1][j-1];
f[i&1][j]=f[i&1][j]+f[(i-1)&1][j];
}
}
ans=zero;
for(register int i=0;i<=k;++i)
for(register int j=i;j<=n;j+=2)
ans=ans+(f[n&1][j]*fac[n-j]*C[j][i]);
for(register int i=0;i<=k;++i)
for(register int j=i+1;j<=n;j+=2)
ans=ans-(f[n&1][j]*fac[n-j]*C[j][i]);
ans.print();
return 0;
}
标签:tor 需要 数组 有序 void getc int 排序 要求
原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/12635821.html