UOJ Round #9 部分题解

A

做完之后翻了翻题解,发现正解是二分?

不过都能AC,时间都是 0 m s 0ms 0ms,差不多了……

显然,要找的点肯定要尽可能排列成正方形,这样可以使得他们之间存在的电线数尽可能多。

然后可以发现,当点数多起来时,比如说取了一个边长为 1 0 4 10^4 104 的正方形,那么他们之间需要 1 0 8 ( 1 0 8 − 1 ) 2 \frac {10^8(10^8-1)} 2 2108(1081) 条电线,然而他们之间一开始存在的电线只有 2 × 1 0 4 × ( 1 0 4 − 1 ) 2\times10^4\times(10^4-1) 2×104×(1041) 条,这样一比,一开始存在的电线数量几乎可以忽略,也就是说,我们能取多少个点,基本取决于 t t t 的大小。

基于这样的想法,我们可以用 t t t 先求出一个尽可能大的正方形,然后一个个点加进去,加到不能加为止即可。

显然,当 t = 1 0 18 t=10^{18} t=1018 时,我们取的正方形的边长大概也就是 1 0 4 10^4 104,点数大概就是 1 0 8 10^8 108 ~ 1 0 9 10^9 109,在 i n t int int 范围内。显然你加点不可能加很多,顶多右边加一列,然后下面加一行,大概就 O ( 2 × 1 0 4 ) O(2\times 10^4) O(2×104),随便跑都能过啦~

但是细节太多了,不好一个一个说……要是有耐心看代码你就看吧qwq

稍微说两个:

  1. 如果 n , m n,m n,m 之中有一个很小,那么可能导致答案是一个长方形而不是正方形。原来加点是右边加一列,然后下面加一行,如果是这种情况那么就只往右加或往下加即可。大概也就加 1 1 1 行(列),脸黑一点可能是 2 2 2 行(列)。
  2. 注意最终点数不能超过 n × m n\times m n×m

代码其实也不长啦:

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long

int n,m; ll t;
int work()
{
    
    
	int p=sqrt(t*2);
	if(1ll*p*(p+1)>t)p--;
	int x,y,v=0,now=0,tot;
	if(n*n>=p)
	{
    
    
		x=y=sqrt(p);
		if(x<1)x=1;if(y<1)y=1;
	}
	else x=n,y=p/n;
	tot=x*y;
	t-=1ll*tot*(tot-1)/2ll-1ll*x*(y-1)-1ll*y*(x-1);
	while(t>=0&&(ll)tot<=(ll)n*m)
	{
    
    
		if(!now)t-=tot-1;else t-=tot-2;
		now++;tot++;
		if(!v)
		{
    
    
			if(now==x)
			{
    
    
				y++,now=0;
				if(x!=n)v^=1;
			}
		}
		else if(now==y)x++,v^=1,now=0;
	}
	if((ll)tot>(ll)n*m)tot=n*m+1;
	return tot-1;
}

int main()
{
    
    
	scanf("%d %d %lld",&n,&m,&t);
	if(n>m)swap(n,m);
	printf("%d",work());
}

B

由于题目保证有解,那么一开始给出的图就是强连通的。

那么尝试给每一条无向边定向,对于一条连接 x , y x,y x,y 的边,假如存在 x x x y y y 的不经过这条边的路径,那么这条边就可以定成 y → x y\to x yx,否则定成 x → y x\to y xy

由于图强连通,所以一定存在两条不相同的路径,一条能让 x x x y y y,一条能让 y y y x x x,所以去掉 x , y x,y x,y 之间的无向边后,至少还存在一条路径,所以根据这条路径定向即可,显然定向完后图依然强连通。

还有,注意重边。

代码如下:

#include <cstdio>
#include <cstring>
#define maxn 5010

int n,m;
struct edge{
    
    int y,next;};
edge e[maxn<<1];
int first[maxn],len=0,tot=0;
int g[maxn][maxn],ans[maxn];
void buildroad(int x,int y)
{
    
    
	e[++len]=(edge){
    
    y,first[x]};
	first[x]=len;g[x][y]++;
}
struct EDGE{
    
    int x,y,type;}road[maxn];
bool v[maxn];
bool dfs(int x,int to)
{
    
    
	if(x==to)return true; v[x]=true;
	for(int i=first[x];i;i=e[i].next)
	if(!v[e[i].y]&&g[x][e[i].y]&&dfs(e[i].y,to))return true;
	return false;
}

int main()
{
    
    
	scanf("%d %d",&n,&m);
	for(int i=1,x,y,z;i<=m;i++)
	{
    
    
		scanf("%d %d %d",&x,&y,&z);road[++tot]=(EDGE){
    
    x,y,z};
		buildroad(x,y);if(!z)buildroad(y,x);
	}
	for(int i=1;i<=m;i++)
	if(!road[i].type)
	{
    
    
		int x=road[i].x,y=road[i].y;g[x][y]--;
		memset(v,false,sizeof(v));ans[i]=1;
		if(!dfs(x,y))g[x][y]++,g[y][x]--,ans[i]=0;
	}
	for(int i=1;i<=m;i++)
	if(road[i].type)printf("0\n");
	else printf("%d\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/a_forever_dream/article/details/109683466