题目描述
题解
止步于此
把边从小到大排序依次加入,维护f[i,j]表示在当前连通块i中有j个团的方案
团只考虑当前加入的边,加入一条边后先把两个块卷积合并(如果不同的话)
然后考虑新增的团,如果当前连通块不是一个团,那么如果要加就只能加一部分,即剩下一些边不加
由于当前边是连通块中最大的,所以不能满足条件
如果是一个团的话那就把f[i,1]+1
卷积的复杂度同树上背包,时间复杂度O(n^2)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%998244353
#define mod 998244353
#define ll long long
//#define file
using namespace std;
int a[1124251][2],fa[1501],s1[1501],s2[1501],n,i,j,k,l,tot,x,y,s;
ll A[1501],f[1501][1501];
int gf(int t) {if (fa[t]==t) return fa[t]; fa[t]=gf(fa[t]);return fa[t];}
int main()
{
#ifdef file
freopen("CF1408G.in","r",stdin);
#endif
scanf("%d",&n),s=n*(n-1)/2;
fo(i,1,n)
{
fa[i]=i;s1[i]=f[i][1]=1;
fo(j,1,n)
{
scanf("%d",&k);
if (i<j) a[k][0]=i,a[k][1]=j;
}
}
fo(i,1,s)
{
x=gf(a[i][0]),y=gf(a[i][1]);
if (x!=y)
{
memset(A,0,sizeof(A));
fo(j,1,s1[x])
{
fo(k,1,s1[y])
add(A[j+k],f[x][j]*f[y][k]);
}
memcpy(f[x],A,sizeof(A));
fa[y]=x,s1[x]+=s1[y],s2[x]+=s2[y]+1;
}
else
++s2[x];
if (s1[x]*(s1[x]-1)/2==s2[x])
++f[x][1];
}
fo(i,1,n) printf("%lld ",f[gf(1)][i]);
printf("
");
fclose(stdin);
fclose(stdout);
return 0;
}