覆盖独立集 - dp

题目大意:给你一张无向图 G ( V , E ) , ∣ V ∣ = n G(V,E),|V|=n G(V,E),V=n,满足存在整数序列 { a n } \{a_n\} {an},使得:
∀ 1 ≤ x &lt; y ≤ n , ∃ ( x , y ) ∈ V ⇐ ⇒ a x &gt; a y \forall1\le x&lt;y\le n,\exist(x,y)\in V\Leftarrow\Rightarrow a_x&gt;a_y 1x<yn,(x,y)Vax>ay
成立。现在问有多少 S ⊆ V S\subseteq V SV,满足:
∀ x , y ∈ S , ̸ ∃ ( x , y ) ∈ E ∀ x ∉ S , ∃ ( x , y ) ∈ E ⇒ y ∈ S \forall x,y\in S,\not\exist(x,y)\in E\\\forall x\notin S,\exist(x,y)\in E\Rightarrow y\in S x,yS,̸(x,y)Ex/S,(x,y)EyS
保证答案小于 2 64 2^{64} 264 n ≤ 1 0 3 n\le10^3 n103
题解:
考虑先用差分约束求出任意一个 G ( V , E ) G(V,E) G(V,E)对应的序列 { a n } \{a_n\} {an}。考虑
( x , y ) ∈ E ⇐ ⇒ a m i n ( x , y ) &gt; a m a x ( x , y ) , ( x , y ) ∉ E ⇐ ⇒ a m i n ( x , y ) ≤ a m a x ( x , y ) (x,y)\in E\Leftarrow\Rightarrow a_{min(x,y)}&gt;a_{max(x,y)},(x,y)\notin E\Leftarrow\Rightarrow a_{min(x,y)}\le a_{max(x,y)} (x,y)Eamin(x,y)>amax(x,y),(x,y)/Eamin(x,y)amax(x,y)
假设 S S S对应的 { a n } \{a_n\} {an}的子序列是 { b m } \{b_m\} {bm}。问题转为求有多少子序列对应的点集满足条件。
第一个条件其实是在要求 S S S G ( V , E ) G(V,E) G(V,E)的一个独立集,对于序列等价于:
∀ x , y ∈ S , x &lt; y , a x ≤ a y \forall x,y\in S,x&lt;y,a_x\le a_y x,yS,x<y,axay
{ b m } \{b_m\} {bm}是一个非降序列。
第二个条件即
∀ x ∉ S , ∃ y ∈ S , a m i n ( x , y ) &gt; a m a x ( x , y ) \forall x\notin S,\exist y\in S, a_{min(x,y)}&gt;a_{max(x,y)} x/S,yS,amin(x,y)>amax(x,y)
这等价于:
∀ x ∉ S , ∃ y ∈ S ⇒ ( y &lt; x ∧ a y &gt; a x ) ∨ ( y &gt; x ∧ a x &gt; a y ) \forall x\notin S,\exist y\in S\Rightarrow(y&lt;x\wedge a_y&gt;a_x)\vee(y&gt;x\wedge a_x&gt;a_y) x/S,yS(y<xay>ax)(y>xax>ay)
由于 { b m } \{b_m\} {bm}是非降序列,二者显然只可能成立一个。
进一步地说,想要让 x ∉ S x\notin S x/S满足条件,只需要考虑其在 S S S中的前驱后继即可。
因此不难发现, { b m } \{b_m\} {bm}合法,当且仅当(记起对应下标为 { c m } \{c_m\} {cm}):
∀ i ∈ [ 0 , m ] , b i ≤ b i + 1 ∧ ( ∀ x ∈ ( c i , c i + 1 ) , a x ∉ ( b i , b i + 1 ) ) \forall i\in[0,m],b_i\le b_{i+1}\wedge \left(\forall x\in(c_i,c_{i+1}),a_x\notin(b_i,b_{i+1}) \right) i[0,m],bibi+1(x(ci,ci+1),ax/(bi,bi+1))
并且钦定 c 0 = 0 , c m + 1 = n + 1 , a 0 = − inf ⁡ , a n + 1 = inf ⁡ c_0=0,c_{m+1}=n+1,a_0=-\inf,a_{n+1}=\inf c0=0,cm+1=n+1,a0=inf,an+1=inf

d p i dp_i dpi表示子序列末尾在 i i i的答案,同时维护
d i , j = max ⁡ k ∈ ( j , i ) , a k ≤ a i a k d_{i,j}=\max_{k\in(j,i),a_k\le a_i}a_k di,j=k(j,i),akaimaxak
最终 d p i = ∑ j ∈ [ 0 , i ) , a j ≤ a i [ a j &gt; d i , j ] d p j dp_i=\sum_{j\in[0,i),a_j\le a_i}[a_j&gt;d_{i,j}]dp_j dpi=j[0,i),ajai[aj>di,j]dpj

时间复杂度 O ( n 2 ) O\left(n^2\right) O(n2)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define N 1010
#define INF (INT_MAX/10-10)
#define inf (INT_MIN/10+10)
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct edges{
    int to,pre,wgt;
}e[N*N];int h[N],etop,g[N][N],a[N],inq[N];ull dp[N];queue<int> q;
inline int add_edge(int u,int v,int w) { return e[++etop].to=v,e[etop].pre=h[u],e[etop].wgt=w,h[u]=etop; }
inline int spfa(int s,int n)
{
    while(!q.empty()) q.pop();
    memset(inq,0,sizeof(int)*(n+1));
    rep(i,1,n) a[i]=-1;
    a[s]=0,q.push(s),inq[s]=1;
    while(!q.empty())
    {
        int x=q.front();q.pop(),inq[x]=0;
        for(int i=h[x],y;i;i=e[i].pre)
            if(a[y=e[i].to]<a[x]+e[i].wgt)
            {
                a[y]=a[x]+e[i].wgt;
                if(!inq[y]) inq[y]=1,q.push(y);
            }
    }
    return 0;
}
int main()
{
    int n=inn(),m=inn(),s=n+1,u,v;
    rep(i,1,m) u=inn()+1,v=inn()+1,g[u][v]=g[v][u]=1;
    rep(i,1,n) rep(j,i+1,n)
        if(g[i][j]) add_edge(j,i,1);
        else add_edge(i,j,0);
    rep(i,1,n) add_edge(s,i,0);
    spfa(s,n+1),a[0]=inf+1,a[n+1]=INF,dp[0]=1;
    rep(i,1,n+1) for(int j=i-1,z=inf;j>=0;j--)
        if(a[j]<=a[i]) { if(z<a[j]) dp[i]+=dp[j];z=max(z,a[j]); }
    return cout<<dp[n+1]<<endl,0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值