BZOJ4715: 囚人的旋律 dp

非常有意思的 dp,很难想出来吧.  

如果对着图去想,很难有思路,所以可以把图上的问题转化为序列问题.    

我们发现,如果一个点集合法,当且仅当这个点集构成一个不降序列,且其他点都与这个点集形成逆序对.   

令 $f[i]$ 表示由 $1$ ~ $i$ (选 $i$ )构成的合法方案数.    

然后如果不选一个元素,显然这个元素必须和距离该元素最近的被选元素形成逆序对.   

假设我们求完 $f[i]$,要去更新 $j$ ($j>i$),则如果中间元素大于 $a[i]$,则中间元素必须大于 $a[j]$.              

小于的情况同理(只要记住更新最大值位置就行)  

#include <bits/stdc++.h>  
#define N 1009   
#define ll long long    
#define mod 1000000007   
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std;     
int val[N][N],f[N];  
int main() 
{ 
    // setIO("input");      
    int n,m;  
    scanf("%d%d",&n,&m);  
    for(int i=1;i<=m;++i) 
    {
        int x,y;  
        scanf("%d%d",&x,&y),val[x][y]=val[y][x]=1; 
    }    
    f[0]=1;  
    for(int i=0;i<=n;++i) 
    {
        int tmp=0;  
        for(int j=i+1;j<=n+1;++j) 
        {
            if((!tmp||val[tmp][j])&&!val[i][j])  
                (f[j]+=f[i])%=mod,tmp=j;   
        } 
    }  
    printf("%d\n",f[n+1]);  
    return 0; 
}

  

posted @ 2020-06-02 11:51  EM-LGH  阅读(262)  评论(0编辑  收藏  举报