CF1408G. Clusterization Counting

题目描述

题解

止步于此

把边从小到大排序依次加入,维护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("\n");
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2020-10-08 15:09  gmh77  阅读(256)  评论(0)    收藏  举报