码迷,mamicode.com
首页 > 其他好文 > 详细

题解 P2159 【[SHOI2009]舞会】

时间:2020-04-05 09:18:26      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:tor   需要   数组   有序   void   getc   int   排序   要求   

传送门

\(first\)

看到数据范围应该都会多多少少有点思路了,要搞一个大概是\(n^3\)\(dp\),可是貌似最多的方案数是\(200!\)级别的,计算器一算发现是\(6e600+\),于是要套高精。所以之前的\(n^3\)排除,将注意力放在\(n^2-n^2logn\),可\(logn\)这种奇怪的复杂度怎么会无缘无故出现在一个\(n<=200\)的题目?于是果断考虑\(n^2dp\)

\(n^2\)都知道什么意思吧,就是设置两个状态的\(dp\)方程

\(second\)

首先应当想到先排序,因为当身高有序后才能方便找出比某一女生矮的男生有多少,以方便进行\(dp\)计算

\(third\)

考虑设置\(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)\)

\(forth\)

但是\(f_{n,j}\)还是不能帮我们解决问题,嗯

但已经接近尾声了,考虑设置\(g_j\)表示选完所有对,而其中至少有\(j\)对的方案数,那么显然\(g_j=f_{n,j} * (n-j)!\)(因为剩下\(n-j\)对没有要求,那么就是全排列嘛)

得到了\(g_j\)数组后就很容易想到容斥得到答案了(容斥系数自己可以瞎搞搞出来):

\[ans=\sum_{i=0}^{k}\sum_{j=i}^{n}(-1)^{j-i}* C_j^i * g_j \]

\(fifth\)

最后一点小注,本篇题解是对该题第一篇题解的一点补充,代码实现思路几乎相同。但由于彼题解有些许瑕疵(也可能是我太蒟蒻)导致没有怎么看懂,后来仔细推敲代码并手搞式子才有了以上这些想法,担心会有和我一样的小菜鸡(应该不会吧)对于首篇的做法有迷惑,于是作此题解来造(bao)福(fu)人(she)类(hui)

\(sixth\)

代码(代码中的\(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;
}

题解 P2159 【[SHOI2009]舞会】

标签:tor   需要   数组   有序   void   getc   int   排序   要求   

原文地址:https://www.cnblogs.com/ALANALLEN21LOVE28/p/12635821.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!