2020牛客暑期多校训练营第四场Investigating Legions

Investigating Legions

原题请看这里

题目描述:

ZYB喜欢阅读侦探小说和侦探漫画。 有一天,他沉迷于这样的故事:
作为B国的间谍,您已经潜伏在A国多年了。 在国家A中有n个部队和m个军团,每个部队仅属于一个军团。 您的任务是调查每个部队属于哪个军团。
一天,你截获了一份记录军队之间关系的情报,从情报中,对于每一对(i,j),可以得到军队i和军队j是否属于同一个军团。然而,每条数据有1/s的独立概率是错误的。
准确的说,军队编号从0到n-1,军团编号从0到m-1。你会给定n(n-1)/2个Boolean型数,表示军队i和军队j是否属于同一军团(1表示是,0表示不是)。每条Boolean型数据有1/S的概率是错误的。你可以认为数据通过以下代码生成:
2020牛客暑期多校训练营第四场Investigating Legions_第1张图片
其中,b[i]表示军队i属于的军团编号。rand()是一个随机生成[0,lcm(m,S)-1]范围内的数的随机函数(玄学)。
现在你知道n和S,但是不知道m的值,请帮B国还原原始数据。

输入描述:

输入包含多组数据。
输入的第一行包含一个整数T (1≤T≤100)表示数据组数
对于每组数据,输入的第一行包含两个整数n,S(30≤n≤300,20≤S≤100)表示部队人数和用于生成数据的整数参数。 在下一行中有一个二进制字符串(即该字符串仅包含“ 0”和“ 1”),其长度为n(n-1)/2,描述成对关系。
它的排列如下:(0,1),(0,2)…(0,n−1),(1,2)…(n−3,n−1),(n−2,n−1).
m没有给出,但是可以保证1≤m≤⌊n/30⌋.所有的T组数据中的n的值不超过1200

输出描述:

对于每种情况,输出整数用空格分隔,第i个整数描述 b e i be_i bei。请以最小的词典顺序输出解决方案。 例如,如果有4个部队和2个地区{0,3},{1,2},你应该输出0 1 1 0.

样例输入:

1
10 20
101110101010101010100010010101010100101010010

样例输出:

0 0 1 0 1 0 1 0 1 0

思路:

打比赛的时候看都没看…
首先,在所给数据中找出 a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3 a n a_n an与a在同一个集合内,然后枚举b,如果b与a在同一集合,但是b与 a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3 a n a_n an不在同一集合,那么显然是错误的。题目中说了有1/S的概率这个数据是错误的(雾),所以需要调参。
所以本题可以通过以下方法做:

for(枚举a)
{
	......
	for(int i=1;i<=n;i++)
	{
		......
		for(枚举b)
		{
			......
		}
		......
	}
	......
	//调参
}

看起来这个代码时间复杂度是O(n^3)!!!但其实循环是跑不满的,第一个循环跑集合个数,第三个循环跑集合元素,所以实际时间复杂度为O(n ^2)

AC Code:

#include
using namespace std;
const int MAXN=2e3+5;
int f[MAXN][MAXN],a[MAXN],n,s,T,id,len,num;
vector<int> v;
char ch;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&s);
		memset(a,-1,sizeof(a));
		memset(f,0,sizeof(f));
		id=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=i+1;j<=n;j++)
			{
				scanf(" %c",&ch);
				f[i][j]=f[j][i]=ch-'0';
			}
			f[i][i]=1;
		}
		for(int i=1;i<=n;i++)
			if(a[i]==-1)
			{
				v.clear();
				for(int j=1;j<=n;j++)
					if(f[i][j]&&a[j]==-1) v.push_back(j);
				len=v.size();
				for(int j=1;j<=n;j++)
				{
					num=0;
					for(int k=0;k<v.size();k++)
						if(f[v[k]][j]&&a[j]==-1) num++;
					if(num*2>=len) a[j]=id;//调参
				}
				id++;
			}
		for(int i=1;i<=n;i++)
			printf("%d ",a[i]);
		printf("\n"); 
	}
}

这代码写的我一愣一愣的,WA了好几发

你可能感兴趣的:(2020牛客暑期多校训练营第四场Investigating Legions)