【洛谷】3月月赛T4-序列-贪心构造&DP

传送门:luoguP5241


题解

一波找规律尝试出 n 4 n^4 n4分做法,然而实际上是个贪心构造转DP:

考虑如何构造出一组合法序列:

首先让所有边首尾相连形成链,如果SCC数量产生变化,就缩链上开头的一部分。

在兼顾SCC数量变化的同时,其它边均贪心地用于串链,直到所有点都被串在了链上——这时就可以随便连了。

在没有将全部点串起来之前,设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示已经串起了前 i i i个点,SCC数量变化了 j j j次,前 k k k个点缩在一起的方案数

在所有点串起来之后,设 g [ i ] [ j ] g[i][j] g[i][j]表示连了 i i i条边,前 j j j个点缩在一起的方案数。(注意 i ≤ ( n 2 ) + ( j 2 ) i\leq {n\choose 2}+{j\choose 2} i(2n)+(2j))

f , g f,g f,g转移均可以前缀和优化,复杂度 O ( n 3 ) O(n^3) O(n3)


代码

#include<bits/stdc++.h>
using namespace std;
const int N=405,mod=1e9+7;

int n,f[N][N],g[N*N][N],ans[N*N];

inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void dc(int &x,int y){x-=y;if(x<0) x+=mod;}

int main(){
	int i,j,k,l,v,bs;f[0][1]=1;
	scanf("%d",&n);bs=n*(n-1)>>1;
	for(i=1;i<n;++i){
	 for(j=0;j<i;++j)
	  for(k=j+1;k<=i;++k)
	   ad(ans[i-1+j],f[j][k]);
	  if(i+1==n) break;
	 for(j=0;j<i;++j){
	  for(v=0,k=j+1;k<=i;++k)
	    {ad(f[j+1][k],v);ad(v,f[j][k]);}
	  ad(f[j+1][i+1],v);
     }
    }
     for(j=0;j+1<n;++j)
      for(k=j+1;k<n;++k)
       ad(g[n-1+j][k],f[j][k]);
    for(i=n-1;i<=n*(n-1);++i){
	  for(j=1;j<=n;++j) ad(ans[i],g[i][j]);
      if(i==n*(n-1)) break;
      for(j=1;j<=n;++j)
      	if(bs+(j*(j-1)/2)>i) ad(g[i+1][j],g[i][j]);
	  for(v=0,j=1;j<=n;++j){
	  	 ad(g[i+1][j],v);ad(v,g[i][j]);
	  }
	}
	for(i=1;i<=n*(n-1);++i){
		printf("%d",ans[i]);
		if(i<n*(n-1)) putchar(' ');
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值