HDU6355 Fireflies 题解
题目描述
\(T\) 组数据,定义全集由 \(\prod_{i=1}^np_i\) 个 \(n\) 维向量组成,其中 \(1\le x_i\le p_i\) 。
对于两个向量 \(X=(x_1,\cdots,x_n),Y=(y_1,\cdots,y_n)\) ,如果 \(x_i-y_i\ge 0,\sum_{i=1}^n(x_i-y_i)=1\) ,那么连一条有向边 \(X\to Y\) 。
求这个集合的可重最小链覆盖。
数据范围
- \(1\le T\le 2000,1\le n\le 32,1\le p_i\le 10^9\) 。
时间限制 \(\texttt{2.5s}\) ,空间限制 \(\texttt{128MB}\) 。
分析
看到可重先做一次传递闭包,那么 \(X\to Y\) 连边当且仅当 \(\forall 1\le i\le n,x_i\ge y_i\) 。
根据\(\text{dilworth}\)定理,最小不可重链覆盖等于最长反链,题意转化为选尽可能多的向量,使得两两没有偏序关系。
根据Sperner定理的推广,我们应该选择满足 \(\sum x_i=c\) 的所有向量,其中 \(c=\lfloor\frac{\sum(p_i+1)}2\rfloor\) 为定值。
于是这道题变成了一个经典问题:求满足 \(1\le x_i\le p_i,\sum_{i=1}^nx_i=c\) 的方案数。
直接容斥,可以算出答案:
至此我们获得了一个 \(\mathcal O(Tn2^n)\) 的做法。
考虑折半优化。
记 \(L=\{1,\cdots,\lfloor\frac n2\rfloor\},R=\{\lfloor\frac n2\rfloor+1,\cdots,n\},f(S)=\sum\limits_{i\in S}p_i\) 。
这里用到组合恒等式 \(\binom{n+m}k=\sum_{i=0}^k\binom ni\binom m{k-i}\) 。
注意 \(n+m\lt 0\) 时不应计入贡献,因此我们需要对 \(f(S),f(T)\) 排序后双指针。
时间复杂度 \(\mathcal O(Tn2^\frac n2)\) 。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fi first
#define se second
#define mp make_pair
#define pii pair<ll,int>
using namespace std;
const int maxn=40,mod=1e9+7;
int m,n,t;
ll c;
int p[maxn];
vector<pii> a,b;
struct mint
{
int val;
mint (ll _val=0)
{
val=_val%mod;
if(val<0) val+=mod;
}
}inv[maxn],sum[maxn];
inline mint operator+(mint x,mint y)
{
if((x.val+=y.val)>=mod) x.val-=mod;
return x;
}
inline mint operator-(mint x,mint y)
{
if((x.val-=y.val)<0) x.val+=mod;
return x;
}
inline mint operator*(mint x,mint y)
{
static ull p=mod,m=(1ull<<63)/p;
ull c=(ull)x.val*y.val;
c-=((__int128)c*m>>63)*p;
if(c>=p) c-=p;
return c;
}
inline void operator+=(mint &x,mint y)
{
x=x+y;
}
inline void operator-=(mint &x,mint y)
{
x=x-y;
}
inline void operator*=(mint &x,mint y)
{
x=x*y;
}
inline mint qpow(mint a,int k)
{
mint res=1;
for(;k;a=a*a,k>>=1) if(k&1) res=res*a;
return res;
}
void work(vector<pii> &a,int *p,int n)
{
a.resize(1<<n);
for(int s=0;s<1<<n;s++)
{
ll cur=0;
for(int i=1;i<=n;i++) if(s>>(i-1)&1) cur+=p[i];
a[s]=mp(cur,__builtin_parity(s)?-1:1);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n),c=0,m=n>>1;
for(int i=1;i<=n;i++) scanf("%d",&p[i]),c+=p[i]+1;
inv[0]=1;
for(int i=1;i<=n-1;i++) inv[i]=inv[i-1]*qpow(i,mod-2);
c>>=1,work(a,p,m),work(b,p+m,n-m);
sort(a.begin(),a.end(),greater<pii>());
sort(b.begin(),b.end());
memset(sum,0,sizeof(sum));
mint res=0;
for(int i=0,j=0;i<a.size();i++)
{
while(j<b.size()&&a[i].fi+b[j].fi<=c-1)
{
mint cur=b[j].se;
for(int k=0;k<=n-1;k++) sum[n-1-k]+=cur*inv[k],cur*=-b[j].fi-k;
j++;
}
mint cur=a[i].se;
for(int k=0;k<=n-1;k++) res+=cur*inv[k]*sum[k],cur*=c-1-a[i].fi-k;
}
printf("%d\n",res.val);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/17240824.html
浙公网安备 33010602011771号