A A A
- 令两类点集合为 S , T S,T S,T,考虑最后的图一定形如一堆 S , T S,T S,T 的连通块以及若干 S S S 其中每个 S S S 连了若干个 T T T,对这个进行 d p dp dp,记 d p i , j dp_{i,j} dpi,j 表示两类点大小下的图个数,枚举连通块转移, O ( n 4 ) O(n^4) O(n4)
#include
#define cs const
#define pb push_back
using namespace std;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a,b); }
void Mul(int &a, int b){ a = mul(a,b); }
void Dec(int &a, int b){ a = dec(a,b); }
int ksm(int a, int b){ int as=1; for(;b;b>>=1,Mul(a,a)) if(b&1) Mul(as,a); return as; }
cs int N = 105;
int T, n, m, C[N][N], pw[N];
int dp[N][N], f[N][N];
void work(int n){
for(int i=0; i<=n; i++)C[i][0]=1;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
C[i][j]=add(C[i-1][j-1],C[i-1][j]);
pw[0]=1;for(int i=1; i<=n; i++)
pw[i]=add(pw[i-1],pw[i-1]);
for(int i=1; i<=n; i++) f[i][0]=1;
for(int i=1; i<=n; i++)
for(int j=1; i+j<=n; j++)
f[i][j]=mul(f[i][j-1],mul(dec(pw[i],1),pw[j-1]));
for(int i=0; i<=n; i++)
dp[i][0]=ksm(2,i*(i-1)>>1);
static int h[N]; h[0]=1;
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
Add(h[i],mul(h[i-j],C[i-1][j-1]));
for(int i=0; i<=n; i++)
dp[0][i]=h[i];
static int z[N]; z[0]=1;
for(int i=1; i<=n; i++){
z[i]=dp[i][0];
for(int j=1; j<i; j++)
Dec(z[i],mul(C[i-1][j-1],mul(z[j],dp[i-j][0])));
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
Mul(f[i][j],z[i]);
for(int i=1; i<=n; i++)
for(int j=1; i+j<=n; j++){
for(int k=1; k<=i; k++)
for(int l=1; l<=j; l++)
Add(dp[i][j],mul(mul(C[i][k],C[j-1][l-1]),mul(dp[i-k][j-l],f[k][l])));
for(int k=1; k<=j; k++)
Add(dp[i][j],mul(dp[i][j-k],C[j-1][k-1]));
}
}
int main(){
#ifdef FSYolanda
freopen("1.in","r",stdin);
#endif
work(100); scanf("%d",&T); while(T--)
scanf("%d%d",&n,&m), cout<<dp[n-m][m]<<'\n';
return 0;
}
B B B
- 考虑最后分为三类点,中间一段的是有贡献的
最小割建图,考虑割与 S S S 表示前缀,割 T T T 的表示后缀,拆点,割中间的表示在中间
对于限制,连边 ( a , b ) , ( a ′ , b ′ ) (a,b),(a',b') (a,b),(a′,b′) 表示 a a a 的段在 b b b 之前
#include
#define cs const
#define pb push_back
using namespace std;
cs int N = 1e4 + 50;
cs int INF = 1e9 + 7;
int fi[N], nxt[N], to[N], w[N], ec=1;
void adde(int x, int y, int z){
nxt[++ec]=fi[x], fi[x]=ec, to[ec]=y, w[ec]=z;
nxt[++ec]=fi[y], fi[y]=ec, to[ec]=x, w[ec]=0;
}
int n, m, a[N], S, T;
int d[N];
bool bfs(){
memset(d,-1,sizeof(d)); d[S]=0;
queue<int> q; q.push(S);
while(!q.empty()){
int x=q.front(); q.pop();
for(int e=fi[x],v;e;e=nxt[e])
if(w[e] && d[v=to[e]]==-1){
d[v]=d[x]+1; q.push(v);
if(v==T) return true;
}
} return false;
}
int dfs(int u, int flw){
if(u==T) return flw; int ans=0;
for(int e=fi[u],v;e;e=nxt[e])
if(d[v=to[e]]==d[u]+1){
int dlt=dfs(v,min(flw,w[e]));
w[e]-=dlt; w[e^1]+=dlt;
ans+=dlt; flw-=dlt; if(!flw) break;
} if(flw)d[u]=-1; return ans;
}
int dinic(){ int flw=0; while(bfs())flw+=dfs(S,INF); return flw; }
int main(){
#ifdef FSYolanda
freopen("1.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
S=0, T=n+n+1;
for(int i=1,u,v; i<=m; i++)
scanf("%d%d",&u,&v),adde(u,v,INF),adde(u+n,v+n,INF);
int ans=0;
for(int i=1; i<=n; i++){
if(a[i]<0)adde(i,i+n,-a[i]);
if(a[i]>0)adde(S,i,a[i]),adde(i+n,T,a[i]),ans+=a[i];
} cout<<ans-dinic()<<'\n';
return 0;
}