2020牛客暑期多校训练营Investigating Legions(黑科技,纠错)

Investigating Legions

题目描述

在这里插入图片描述

输入描述:

在这里插入图片描述

输出描述:

在这里插入图片描述

示例1

输入

1
10 20
101110101010101010100010010101010100101010010

输出

0 0 1 0 1 0 1 0 1 0

备注:

在这里插入图片描述

题目大意

给定 n n s s 。然后有 n n 个点, m m 个集合,对于点 i i j j ,有 f ( i , j ) f(i,j) 表示 i i j j 是否在同一集合里,求每个点在第几个集合中。
但是,题目中的的数据有 1 s \frac{1}{s} 的概率是错的!?(傻了

分析

这题比赛时根本没去看,完了之后老师讲了再做的。

首先对于 a a ,在题目给出的数据中找出 a 1 a_1 , a 2 a_2 , a 3 a_3 …… a n a_n a a 在同一集合,然后枚举 b b ,如果 b b a a 在同一集合,然而 b b 和其他与 a a 同一集合的点若不在同一集合,那么显然是不对的。但是题目里说了,有 1 s \frac{1}{s} 的概率是错的,所以可以判下。这里就有点调参的性质,后文中采用 1 2 \frac{1}{2}

因此我们只要
for(枚举a)
for(找到与a在同一集合的)
for(枚举b)
看起来是个O(n3)的算法,但是其实没有跑满的,
可以想见,第一层的for是跑集合个数,第三层是跑集合元素。合起来是O(n),
因此总的复杂度其实只有O(n2)。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=310;
int f[MAXN][MAXN],a[MAXN];
char ff[MAXN*MAXN];
vector<int> vec;
int main()
{
	int t,n,s;
	for(scanf("%d",&t);t--;){
		scanf("%d%d%s",&n,&s,ff);
		int cnt=0,num=0;
		for(int i=0;i<n;i++){
			for(int j=i+1;j<n;j++){
				f[i][j]=f[j][i]=ff[cnt++]-'0';
			}
			f[i][i]=1;
		}cnt=0;
		fill(a,a+1+n,-1);
		for(int i=0;i<n;i++){//枚举a
			vec.clear();
			if(a[i]!=-1) continue;
			for(int j=0;j<n;j++)//找和a是同个集合的元素
				if(f[i][j]&&a[j]==-1)
					vec.push_back(j);
			for(int j=0;j<n;j++)//枚举b
			if(a[j]==-1){
				num=0;
				for(int k=0;k<vec.size();k++)
					if(f[vec[k]][j]) num++;
				if(num>=vec.size()/2) a[j]=cnt;//如果大于1/2,就合法。
			}
			cnt++;
		}
		for(int i=0;i<n;i++) printf("%d ",a[i]);
		printf("\n");
	}
}

END

玄学题目。搞到去世。

猜你喜欢

转载自blog.csdn.net/zhangchizc/article/details/107490550