题目大意:给你一张无向图
,满足存在整数序列
,使得:
成立。现在问有多少
,满足:
保证答案小于
,
。
题解:
考虑先用差分约束求出任意一个
对应的序列
。考虑
假设
对应的
的子序列是
。问题转为求有多少子序列对应的点集满足条件。
第一个条件其实是在要求
是
的一个独立集,对于序列等价于:
即
是一个非降序列。
第二个条件即
这等价于:
由于
是非降序列,二者显然只可能成立一个。
进一步地说,想要让
满足条件,只需要考虑其在
中的前驱后继即可。
因此不难发现,
合法,当且仅当(记起对应下标为
):
并且钦定
令
表示子序列末尾在
的答案,同时维护
最终
时间复杂度
#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;
}