[洛谷P3940]:分组(贪心+并查集)

题目传送门


题目描述

小$C$在了解了她所需要的信息之后,让兔子们调整到了恰当的位置。小$C$准备给兔子们分成若干个小组来喂恰当的胡萝卜给兔子们吃。
此时,$n$只兔子按一定顺序排成一排,第$i$只兔子的颜色是$a_i$。由于顺序已经是被调整好了的,所以每个小组都应当是序列上连续的一段
在分组前,小$C$发现了一个规律:有些兔子会两两发生矛盾。并且,两只兔子会发生矛盾,当且仅当代表他们的颜色的数值之和为一个正整数的平方。比如,$1$色兔子和$2$色兔子不会发生矛盾,因为$3$不是任何一个正整数的平方;而$1$色兔子却会和$3$色兔子发生矛盾,因为$4=2^2$。
小$C$认为,只要一个小组内的矛盾不要过大就行。因此,小$C$定义了一个小组的矛盾值$k$,表示在这个小组里,至少需要将这个组再一次分成$k$个小团体;每个小团体并不需要是序列上连续的一段,但是需要使得每个小团体内任意两只兔子之间都不会发生矛盾。
小$C$要求,矛盾值最大的小组的矛盾值$k$不超过$K$就可以了。当然,这样的分组方法可能会有很多个;为了使得分组变得更加和谐,小$C$想知道,在保证分组数量最少的情况下,字典序最小的方案是什么。你能帮帮她吗?
字典序最小的方案是指,按顺序排列分组的间隔位置,即所有存在兔子$i$和$i+1$在不同组的位置。


输入格式

输入第1行两个正整数$n,K$。
输入第2行$n$个正整数,第$i$个数表示第$i$只兔子的颜色$a$。


输出格式

输出第$1$行一个正整数$m$,为你至少需要将兔子分为多少个小组。
输出第$2$行$m-1$个从小到大的排列的正整数,第$i$个数$s_i$表示$s_i$和$s_{i+1}$在你的方案里被分到了两个小组。如果$m=1$,那么请输出一个空行。


样例

样例输入1:

5 2
1 3 15 10 6

样例输出1:

2
1

样例输入2:

319 2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

样例输出2:

6
7 31 71 127 199


数据范围与提示

样例1解释:

如果将五只兔子全部分到同一个小组的话,那么$(1,3)(3,6)(6,10)(10,15)(1,15)$均不能分到同一个小团体;因为最多分成两个小团体,所以为了满足前4对限制,只能分为$\{\{1,6,15\},\{3,10\}\}$,但此时不满足$(1,15)$,所以不存在一种组数为$1$的方案满足全部限制。
如果将五只兔子分为两个小组的话,一种字典序最小的可行的分组方案是$\{1\},\{3,15,10,6\}$,此时第二组内的小团体数量不超过$2$的一种分法是$\{\{3,10\},\{15,6\}\}$。

数据范围:

$K=1||2$

$n\leqslant 131076$

$a_i\leqslant 131072$


题解

对于$K=1$:

 测试点$1$:$n=2$

  直接判一下两数值和是否为完全平方数。

  是就$puts("2$ \ $n1");$,不是就$puts("1$ \ $n");$。

  时间复杂度:$\Theta(1)$。

  期望得分:$4$分。

  总得分:$4$分。

 测试点$2$:$n=4$

  手动讨论所有情况即可。

  时间复杂度:$\Theta(1)$。

  期望得分:$4$分。

  总得分:$8$分。

 测试点$3$:$n=16$

  暴力搜索,可以得到所有的分组情况,一个一个验证就好了。

  时间复杂度:$\Theta(2^n\times n^2)$。

  期望得分:$12$分。

  总得分:$12$分。


代码时刻

测试点$1$:

#include<bits/stdc++.h>
using namespace std;
int a[131073];
int main()
{
	int n,K;
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	if(K==1)
	{
		if(n==2)
			if((int)sqrt(a[1]+a[2])*(int)sqrt(a[1]+a[2])==a[1]+a[2])puts("2\n1");
			else puts("1\n");
	}		
	return 0;
}

测试点$2$:

#include<bits/stdc++.h>
using namespace std;
int a[131073];
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==x+y?0:1;}
void judge0()
{
	if(asksqr(a[1],a[2])&&asksqr(a[1],a[3])&&asksqr(a[1],a[4])&&asksqr(a[2],a[3])&&asksqr(a[2],a[4])&&asksqr(a[3],a[4])){puts("1\n");exit(0);}
}
void judge1()
{
	if(asksqr(a[2],a[3])&&asksqr(a[2],a[4])&&asksqr(a[3],a[4])){puts("2\n1");exit(0);}
	if(asksqr(a[1],a[2])&&asksqr(a[3],a[4])){puts("2\n2");exit(0);}
	if(asksqr(a[1],a[2])&&asksqr(a[1],a[3])&&asksqr(a[2],a[3])){puts("2\n3");exit(0);}
}
void judge2()
{
	if(asksqr(a[3],a[4])){puts("3\n1\n2");exit(0);}
	if(asksqr(a[2],a[3])){puts("3\n1\n3");exit(0);}
	if(asksqr(a[1],a[2])){puts("3\n3\n3");exit(0);}
}
void judge3(){puts("4\n1\n2\n3");exit(0);}
int main()
{
	int n,K;
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	if(K==1)
	{
		if(n==4)
		{
			judge0();
			judge1();
			judge2();
			judge3();
		}
	}		
	return 0;
}

测试点$3$:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[131073];
int ans[131072],cnt;
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==x+y?1:0;}
bool judge()
{
	for(int i=1;i<=cnt;i++)
		for(int j=ans[i-1]+1;j<ans[i];j++)
			for(int k=j+1;k<=ans[i];k++)
				if(asksqr(a[j],a[k]))return 0;
	for(int i=ans[cnt]+1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			if(asksqr(a[i],a[j]))return 0;
	return 1;
}
void print()
{
	printf("%d\n",cnt+1);
	for(int i=1;i<=cnt;i++)
		printf("%d ",ans[i]);
}
void dfs(int x,int l,int w)
{
	if(x==w){if(judge()){print();exit(0);}return;}
	for(int i=l;i<n;i++)
	{
		ans[++cnt]=i;
		dfs(x+1,i+1,w);
		cnt--;
	}
}
int main()
{
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	if(K==1)
	{
		for(int i=0;i<n;i++)dfs(0,1,i);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11297146.html