牛客第7场多校E Counting 4-Cliques

考场上脑补了好多种姿势,都不太对,不过确实当时状态太差了,没睡好脑袋很沉,一直都有划水的想法,根本不想去想题,然而还是要想,就并想不出来。估计艹过去的姿势很多,不过题解的那种我并不太会证明,题解是先选一个满矩阵,点数为n,c(n,4)<=k,n从4到70中选,然后再开5个互不相连的点,去连满矩阵里的点,一个点连r个,就多c(r,3)个,70^4枚举前4个,然后二分一蛤找第5个。本来我是71上限选4个,然而这样WA,84%,前面的我都手测过没问题,可能后面有些点达不到,不过70,枚举5个就过了70^4log(70),看似很大,不过我们枚举规定一个顺序,前面的点多,后面的点不超过前面的,常数就小很多,11ms就跑过去了。。。

#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib> 
#include<algorithm>
#define maxl 76

using namespace std;

int n,k;
bool vis[maxl][maxl];

inline int c3(int r)
{
	if(r<3)
		return 0;
	return r*(r-1)*(r-2)/6;
} 

inline int c4(int r)
{
	if(r<4)
		return 0;
	return r*(r-1)*(r-2)*(r-3)/24;
}

inline void prework()
{
	n=0;
	for(int i=4;i<=70;i++)
	if(c4(i)<=k && c4(i+1)>k)
	{
		n=i;
		break;
	}
	if(n==0)
		n=70;
}

inline void solve(int d1,int d2,int d3,int d4,int d5)
{
	for(int i=1;i<=d1;i++)
		vis[n+1][i]=true,vis[i][n+1]=true;
	for(int i=1;i<=d2;i++)
		vis[n+2][i]=true,vis[i][n+2]=true;
	for(int i=1;i<=d3;i++)
		vis[n+3][i]=true,vis[i][n+3]=true;
	for(int i=1;i<=d4;i++)
		vis[n+4][i]=true,vis[i][n+4]=true;
	for(int i=1;i<=d5;i++)
		vis[n+5][i]=true,vis[i][n+5]=true;
}

inline int find(int d5)
{
	int l=0,r=n,mid;
	while(l+1<r)
	{
		mid=(l+r)>>1;
		if(c3(mid)<d5)
			l=mid;
		else
			r=mid;
	}
	if(c3(l)==d5)
		return l;
	else
	if(c3(l+1)==d5)
		return l+1;
	else
		return 0;
}

inline void mainwork()
{
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			vis[i][j]=true,vis[j][i]=true;
	int sum,h;
	for(int i=0;i<=n;i++)
		for(int j=0;j<=i;j++)
			for(int l=0;l<=j;l++)
				for(int t=0;t<=l;t++)
				{
					sum=c4(n)+c3(i)+c3(j)+c3(l)+c3(t);
					h=find(k-sum);
					if(sum+c3(h)==k)
					{
						solve(i,j,l,t,h);
						return;
					}
				}
}

inline void print()
{
	int m=0;n+=5;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		if(vis[i][j])
			m++;
	printf("%d %d\n",n,m);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
		if(vis[i][j])
			printf("%d %d\n",i,j);
	int cnt=0;
/*	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			for(int l=j+1;l<=n;l++)
				for(int t=l+1;t<=n;t++)
				if(vis[i][j] && vis[i][l] && vis[i][t]
				 &&vis[j][l] && vis[j][t] && vis[l][t])
				 	cnt++;
	printf("%d\n",cnt);*/
}

int main()
{
	srand(time(0));
	while(~scanf("%d",&k))
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81559049
今日推荐