您的位置:首页 > 其它

BZOJ 3622 已经没有什么好害怕的了

2017-01-18 20:51 387 查看
DP+容斥

然而这题还是令我很害怕。



最值问题的DP一般考虑排序之后从小到大或从大到小,一个一个地考虑。

对于这题,对A,B排序,记next[i]=j,表示最大的j满足B[j] < A[i],不难想到方程f[i][j]表示做到A的第i个,其中已经有j对满足A>B,然后转移

f[i][j] = f[i-1][j] + f[i-1][j-1] * (next[i] - j + 1)

但是这是错的,因为我们只钦定了有j对大于,并不能确定剩下的n-j对就一定是小于。一般想到这里就觉得这个DP没用了。然而这题妙在可以直接容斥减去不合法状态。。。

记g[i][j]表示做到A的第i位,恰好有j对满足A>B。

我们考虑f
[j]中重复出现的东西到底出现了多少次。

对于恰好j对的方案,一定是不重不漏地都被统计了,因为这j对一定恰好被钦定了。

对于恰好j+1的方案,有C(j+1,j)种方案能选出j个来被钦定,因此它被统计了C(j+1,j)。

实际上恰好k的方案就统计了C(k,j)次。我们把g乘上这个系数减掉即可。

#include<cstdio>
#include<algorithm>
#define MOD 1000000009
#define N 2005
using namespace std;
namespace runzhe2000
{
typedef long long ll;
const int INF = 1<<30;
int a
, b
, next
, f

, g
, c

, n, k, fac
;
void init()
{
c[0][0] = 1; fac[0] = 1;
for(int i = 1; i <= n; i++)
{
c[i][0] = 1;
for(int j = 1; j <= i; j++)
c[i][j] = (c[i-1][j] + c[i-1][j-1]) % MOD;
fac[i] = (ll)fac[i-1] * i % MOD;
}
}
void main()
{
scanf("%d%d",&n,&k);
if((n+k)&1){puts("0"); return;}
init();
for(int i = 1; i <= n; i++) scanf("%d",&a[i]); sort(a+1, a+1+n);
for(int i = 1; i <= n; i++) scanf("%d",&b[i]); sort(b+1, b+1+n); b[n+1] = INF;
for(int i = 1; i <= n; i++)
{
int p = next[i-1];
for(; b[p+1] < a[i]; p++);
next[i] = p;
}
f[0][0] = 1;
for(int i = 1; i <= n; i++)
{
f[i][0] = 1;
for(int j = 1; j <= i; j++)
f[i][j] = (f[i-1][j] + (ll)f[i-1][j-1] * (next[i] - j + 1)) % MOD;
}
for(int i = n; i; i--)
{
f
[i] = (ll)f
[i] * fac[n-i] % MOD;
for(int j = n; j > i; j--)
{
f
[i] = (f
[i] - (ll)g[j] * c[j][i]) % MOD;
}
g[i] = f
[i];
}
printf("%d\n",(g[(n+k)/2]+MOD) % MOD);
}
}
int main()
{
runzhe2000::main();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: