题目传送门


题目描述

小$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$           $n$                 $a_i,c_j$               特殊性质$1$           特殊性质$2$
    $1$             $1$           $2$                 $\leqslant 131072$              $\surd$                          $\times$
    $2$             $1$           $4$                 $\leqslant 131072$              $\times$                          $\times$
    $3$             $1$          $16$               $\leqslant 131072$               $\times$                          $\times$
    $4$             $1$          $256$             $\leqslant  131072$              $\surd$                          $\times$
    $5$             $1$          $1024$          $\leqslant 131072$              $\surd$                          $\times$
    $6$             $1$          $1024$          $\leqslant 131072$              $\times$                          $\times$
    $7$             $1$          $131072$     $\leqslant 2$                          $\surd$                          $\times$
    $8$             $1$          $131072$     $\leqslant 131072$              $\surd$                          $\times$
    $9$             $1$          $131072$     $\leqslant 131072$              $\times$                          $\surd$
    $10$           $1$         $131072$      $\leqslant 131072$              $\times$                          $\times$
    $11$           $2$         $2$                  $\leqslant 131072$              $\surd$                          $\times$
    $12$           $2$         $4$                  $\leqslant 131072$              $\times$                          $\times$
    $13$           $2$         $8$                  $\leqslant 131072$              $\times$                          $\times$
    $14$           $2$         $16$               $\leqslant 131072$               $\times$                          $\times$
    $15$           $2$         $256$             $\leqslant 131072$              $\surd$                          $\times$
    $16$           $2$         $256$             $\leqslant 131072$              $\times$                          $\surd$
    $17$           $2$         $1024$           $\leqslant 2$                          $\surd$                          $\times$
    $18$           $2$         $1024$           $\leqslant 131072$              $\times$                          $\times$
    $19$           $2$         $4096$           $\leqslant 2$                          $\times$                           $\times$
    $20$           $2$         $4096$           $\leqslant 131072$              $\times$                          $\times$
    $21$           $2$         $131072$      $\leqslant 2$                           $\times$                          $\times$
    $22$           $2$         $131072$      $\leqslant 131072$              $\times$                          $\surd$
    $23$           $2$         $131072$      $\leqslant 131072$              $\times$                          $\surd$
    $24$           $2$         $13102$        $\leqslant 131072$              $\times$                          $\times$
    $25$           $2$         $131072$      $\leqslant 131072$              $\times$                          $\times$


题解

对于$K=1$:

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

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

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

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

  期望得分:$4$分。

  实际得分:$4$分。

  总得分:$4$分。

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

  手动讨论所有情况即可。

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

  期望得分:$4$分。

  实际得分:$4$分。

  总得分:$8$分。

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

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

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

  期望得分:$12$分。

  实际得分:$12$分。

  总得分:$12$分。

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

  考虑$DP$。

  预处理$f[i][j]$表示从$i$到$j$可以分到一组。

  定义$dp[i][j]$表示,此时已经分到了第$i$个位置,已经分了$k$组,方案可行$or$不可行($0$/$1$表示。

  则$DP$式子为:$dp[i][k]|=dp[j][k-1]\&\&f[j+1][i]$。

  在开一个数组记录一下上次转移的位置,为保证最优性,已经转移过不再更新,判断一下就好了。

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

  期望得分:$16$分。

  实际得分:$24$分。

  总得分:$24$分。

 测试点$5,6$:$n=1024$

  发现上面的解法中$k$那一维可以去掉,即:$if(f[j+1][i])dp[i]=\min(dp[i],dp[j]+1)$。

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

  期望得分:$24$分。

  实际得分:$24$分。

 测试点$7\thicksim 10$:$n=131072$

  根据我们刚刚的结论,细心的你一定会发现:

  其实这个$DP$并不是一个$DP$,本质上是找最长的合法分段,然后把问题转化为子问题。

  问题可以转化为:从前往后,选择一段最长的合法区间并分割,重新进行知道完成为止。

  为什么要从后往前呢?因为我们要保证在最优的情况下断点的字典序最小,所以我们需要让断点尽可能的靠前,然而从前往后搜我们并不知道什么时候该断才是最优的,所以我们就可以从后往前搜,尽可能的靠后断,就能保证答案最优了。

  我们可以在每插入一个点时逐一判断是否不合法。

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

  期望得分:$24$分。

  实际得分:$32$分。

  总得分:$32$分。

  显然上面的这种方法会让你$T$到飞起,所以考虑如何优化。

  悄悄的观察数据范围会惊喜的发现$a_i\leqslant 131072$,那么就意味着$a_i+a_j=262144={512}^2$,所以我们在插入一个数的时候可以枚举$x$,看$x^2-a_j$有没有出现过即可。

  时间复杂度:$\Theta(n\sqrt{n})$。

  期望得分:$40$分。

  实际得分:$40$分。

  总得分:$40$分。

这样,我们对$K=1$的情况就拿满分了。

对于$K==2$:

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

  无论如何,一组也够了(出题人好良心……)。

  直接$puts("1$\ $n");$就好啦。

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

  期望得分:$4$分。

  实际得分:$4$分。

  总得分:$44$分。

 测试点$12\thicksim 14$:

  枚举分组,判定是否合法。

  如何判定合法?

  可以再次进行暴力分组。

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

  其实没有必要,把会发生矛盾的兔子连边,发现这就是个二分图判定,黑白染色即可。

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

  期望得分:$16$分。

  实际得分:$16$分。

  总得分:$56$分。

 测试点$15\thicksim 18$:

  根据之前的结论,发现我们就是找判定最长序列。

  每次判定时建一个图进行判定,直到非法为止。

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

  期望得分:$24$分。

  实际得分:$32$分。

  总得分:$72$分。

 测试点$19\thicksim 25$:

  发现我们上面的用二维数组记录敌对关系是一种限制,所以我们可以考虑使用带权并查集来存储关系。

  可以仿照$K=1$的思想进行统计答案。

  但是需要注意一个问题:

    如果某个数出现了多次,如果这个数的二倍是一个完全平方数,那么就不能丢到同一组;否则不管有多少个也不用担心(注意还不能有第三个数与它们敌对)。

  时间复杂度:$\Theta(n\times \sqrt{\max(a_i)})$。

  期望得分:$60$分。

  实际得分:$60$分。

  总得分:$100$分。

到这里,我们就成功的解决了这道题~~~


代码时刻

测试点$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;
}

测试点$4$:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[131073];
bool f[1050][1050],dp[1050][1050];
int flag[1050][1050];
int ans[1050];
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==(x+y)?0:1;}
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dp[i][i]=1;
}
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=i;k<j;k++)
if(!asksqr(a[j],a[k]))goto nxt;
f[i][j]=f[j][i]=1;
}
nxt:;
}
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
for(int k=1;k<=n;k++)
{
dp[i][k]|=dp[j][k-1]&f[j+1][i];
if(dp[j][k-1]&&f[j+1][i]&&!flag[i][k])flag[i][k]=j;
}
for(int i=1;i<=n;i++)
if(dp[n][i])
{
printf("%d\n",i);
int now=n;
int k=i;
while(now)
{
ans[++ans[0]]=flag[now][k];
now=flag[now][k--];
}
break;
}
for(int i=ans[0]-1;i;i--)
printf("%d ",ans[i]);
return 0;
}

测试点$5,6$:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[131073];
bool f[1050][1050];
int dp[1050];
int flag[1050][1050];
int ans[1050];
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==(x+y)?0:1;}
int main()
{
scanf("%d%d",&n,&K);
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
for(int k=i;k<j;k++)
if(!asksqr(a[j],a[k]))goto nxt;
f[i][j]=f[j][i]=1;
}
nxt:;
}
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
if(f[j+1][i])
{
dp[i]=min(dp[i],dp[j]+1);
if(!flag[i][dp[j]+1])flag[i][dp[j]+1]=j;
}
printf("%d\n",dp[n]-1);
int now=n;
int k=dp[n];
while(now)
{
ans[++ans[0]]=flag[now][k];
now=flag[now][k--];
}
for(int i=ans[0]-1;i;i--)
printf("%d ",ans[i]);
return 0;
}

测试点$7\thicksim 10$($32$分):

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[150000];
bool flag[300000];
int que[150000],sum;
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=512;i++)flag[i*i]=1;
if(K==1)
{
int l=n;
for(int i=n;i;i--)
for(int j=l;j>i;j--)
if(flag[a[i]+a[j]])
{
l=i;
que[++sum]=i;
break;
}
printf("%d\n",sum+1);
for(int i=sum;i;i--)printf("%d ",que[i]);
}
return 0;
}

测试点$7\thicksim 10$($40$分):

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[150000],maxn;
bool vis[150000];
int que[150000],sum;
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++){scanf("%d",&a[i]);maxn=max(maxn,a[i]);}
if(K==1)
{
for(int i=n,j=n;i;)
{
for(;j;j--)
{
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<=0)continue;
if(vis[k*k-a[j]])goto nxt;
}
vis[a[j]]=1;
}
nxt:
if(!j)break;
que[++sum]=j;
for(;i>j;i--)vis[a[i]]=0;
}
printf("%d\n",sum+1);
for(int i=sum;i;i--)printf("%d ",que[i]);
}
return 0;
}

测试点$11$:

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

测试点$12\thicksim 15$(二分图):

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[131073];
int ans[131072],col[131072],que[131072],cnt;
bool Map[30][30],flag[30],vis[30];
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==x+y?1:0;}
bool color_solve(int x,int color)//判定二分图
{
col[x]=color;
vis[x]=1;
for(int i=1;i<=n;i++)
{
if(i==x||!flag[i]||!Map[x][i])continue;
if(col[i]==color)return 1;
if(!col[i]&&color_solve(i,-color))return 1;
}
return 0;
}
bool judge()
{
for(int i=1;i<=cnt;i++)
{
que[0]=0;
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
memset(col,0,sizeof(col));
for(int j=ans[i-1]+1;j<=ans[i];j++)
{que[++que[0]]=j;flag[j]=1;}
for(int j=1;j<=que[0];j++)
if(!vis[que[j]])if(color_solve(que[j],1))return 0;
}
que[0]=0;
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
memset(col,0,sizeof(col));
for(int i=ans[cnt]+1;i<=n;i++)
{que[++que[0]]=i;flag[i]=1;}
for(int i=1;i<=que[0];i++)
if(!vis[que[i]])if(color_solve(que[i],1))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]);
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
Map[i][j]=Map[j][i]=asksqr(a[i],a[j]);
if(K==2)
{
for(int i=0;i<n;i++)
dfs(0,1,i);
}
return 0;
}

测试点$15\thicksim 18$:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[131073];
int ans[131072],col[131072],que[131072],sum;
bool Map[1050][1050],flag[1050],vis[1050];
bool asksqr(int x,int y){return (int)sqrt(x+y)*(int)sqrt(x+y)==x+y?1:0;}
bool color_solve(int x,int color)
{
col[x]=color;
vis[x]=1;
for(int i=1;i<=n;i++)
{
if(i==x||!flag[i]||!Map[x][i])continue;
if(col[i]==color)return 1;
if(!col[i]&&color_solve(i,-color))return 1;
}
return 0;
}
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
Map[i][j]=Map[j][i]=asksqr(a[i],a[j]);
if(K==2)
{
int l=n;
for(int i=n;i;i--)
{
que[0]=0;
memset(vis,0,sizeof(vis));
memset(flag,0,sizeof(flag));
memset(col,0,sizeof(col));
for(int j=l;j>=i;j--)
{
que[++que[0]]=j;
flag[j]=1;
}
for(int j=1;j<=que[0];j++)
if(!vis[que[j]])
if(color_solve(que[j],1))
{
l=i;
ans[++sum]=i;
break;
}
}
printf("%d\n",sum+1);
for(int i=sum;i;i--)printf("%d ",ans[i]);
}
return 0;
}

测试点$19\thicksim 25$:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[150000],maxn;
bool vis[150000],sit[150000];
int que[150000],sum;
int fa[300000];
int find(int x){return fa[x]<=0?x:fa[x]=find(fa[x]);}
void connect(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
if(fa[x]>fa[y]){fa[y]+=fa[x];fa[x]=y;}
else {fa[x]+=fa[y];fa[y]=x;}
}
}
bool judge(int x, int y)
{
int flag1=find(x),flag2=find(x+140000),flag3=find(y),flag4=find(y+140000);
if(flag1==flag3)return 1;
if(flag2==flag4)return 1;
connect(flag1,flag4);
connect(flag2,flag3);
return 0;
}
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++){scanf("%d",&a[i]);maxn=max(maxn,a[i]);}
if(K==2)
{
for(int i=n,j=n;i;)
{
for(;j;j--)
{
if(vis[a[j]])
{
if((int)sqrt(a[j]<<1)*(int)sqrt(a[j]<<1)==a[j]<<1)
{
if(sit[a[j]])break;
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<0)continue;
if(vis[k*k-a[j]]&&k*k!=a[j]<<1)goto nxt;
}
sit[a[j]]=1;
}
}
else
{
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<=0)continue;
if(vis[k*k-a[j]]&&(judge(k*k-a[j],a[j])||sit[a[j]]||sit[k*k-a[j]])){fa[a[j]]=fa[a[j]+140000]=0;goto nxt;}
}
vis[a[j]]=1;
}
}
nxt:
if(!j)break;
que[++sum]=j;
for(;i>j;i--)fa[a[i]]=fa[a[i]+140000]=vis[a[i]]=sit[a[i]]=0;
}
printf("%d\n",sum+1);
for(int i=sum;i;i--)printf("%d ",que[i]);
}
return 0;
}

$100$分代码:

#include<bits/stdc++.h>
using namespace std;
int n,K;
int a[150000],maxn;
bool vis[150000],sit[150000];
int que[150000],sum;
int fa[300000];
void solve1()
{
for(int i=n,j=n;i;)
{
for(;j;j--)
{
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<=0)continue;
if(vis[k*k-a[j]])goto nxt;
}
vis[a[j]]=1;
}
nxt:
if(!j)break;
que[++sum]=j;
for(;i>j;i--)vis[a[i]]=0;
}
}
int find(int x){return fa[x]<=0?x:fa[x]=find(fa[x]);}
void connect(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
if(fa[x]>fa[y]){fa[y]+=fa[x];fa[x]=y;}
else {fa[x]+=fa[y];fa[y]=x;}
}
}
bool judge(int x, int y)
{
int flag1=find(x),flag2=find(x+140000),flag3=find(y),flag4=find(y+140000);
if(flag1==flag3)return 1;
if(flag2==flag4)return 1;
connect(flag1,flag4);
connect(flag2,flag3);
return 0;
}
void solve2()
{
for(int i=n,j=n;i;)
{
for(;j;j--)
{
if(vis[a[j]])
{
if((int)sqrt(a[j]<<1)*(int)sqrt(a[j]<<1)==a[j]<<1)
{
if(sit[a[j]])break;
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<0)continue;
if(vis[k*k-a[j]]&&k*k!=a[j]<<1)goto nxt;
}
sit[a[j]]=1;
}
}
else
{
for(int k=1;k*k-a[j]<=maxn;k++)
{
if(k*k-a[j]<=0)continue;
if(vis[k*k-a[j]]&&(judge(k*k-a[j],a[j])||sit[a[j]]||sit[k*k-a[j]])){fa[a[j]]=fa[a[j]+140000]=0;goto nxt;}
}
vis[a[j]]=1;
}
}
nxt:
if(!j)break;
que[++sum]=j;
for(;i>j;i--)fa[a[i]]=fa[a[i]+140000]=vis[a[i]]=sit[a[i]]=0;
}
}
int main()
{
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++){scanf("%d",&a[i]);maxn=max(maxn,a[i]);}
if(K==1)solve1();
else solve2();
printf("%d\n",sum+1);
for(int i=sum;i;i--)printf("%d ",que[i]);
return 0;
}

rp++

[洛谷P3940]:分组(贪心+并查集)的更多相关文章

  1. bzoj3673 & bzoj3674 & 洛谷P3402 可持久化并查集

    题目:bzoj3673:https://www.lydsy.com/JudgeOnline/problem.php?id=3673 bzoj3674:https://www.lydsy.com/Jud ...

  2. 洛谷P1525关押罪犯——并查集

    题目:https://www.luogu.org/problemnew/show/P1525 并查集+贪心,从大到小排序,将二人分在不同房间,找到第一个不满足的即为答案. 代码如下: #include ...

  3. 洛谷 3295 [SCOI2016]萌萌哒——并查集优化连边

    题目:https://www.luogu.org/problemnew/show/P3295 当要连的边形如 “一段区间内都是 i 向 i+L 连边” 的时候,用并查集优化连边. 在连边的时候,如果要 ...

  4. 洛谷P2024 食物链 [NOI2001] 并查集

    正解:并查集 解题报告: 传送门(咕了! 其实没有很难(虽然我是交了三发才过的QAQ 但是一来好久没打并查集了恢复一下智力 二来看着智推里唯一一个蓝就很不爽(,,,虽然做了这题之后又补上了个蓝题QAQ ...

  5. 洛谷P1197 [JSOI2008] 星球大战 [并查集]

    题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...

  6. 洛谷 P1551 亲戚(并查集模板)

    嗯... 题目链接:https://www.luogu.org/problemnew/show/P1551 思路: 很显然地我们会发现,这是一道并查集的模板题,并且是考察了并查集中的”并“和”查“的操 ...

  7. 洛谷P1111修复公路并查集改

    看了他们的题解感觉很震惊,为什么要用kruskal,这题要用到最小生成树吗??? 38行短短的程序就可以了,我觉得学习不是一种套用,套自己学的,而且题解很大一部分都是kruskal. 个人认为自己的程 ...

  8. 洛谷 - P5429 - Fence Planning - 并查集

    https://www.luogu.org/problemnew/show/P5429 很明显是要维护整个连通块的共同性质,并查集一搞就完事了. #include<bits/stdc++.h&g ...

  9. 洛谷 - P4997 - 不围棋 - 并查集 - 模拟

    https://www.luogu.org/problemnew/show/P4997 首先是改变气的定义,使得容易计算,这个很好理解. 然后使用并查集,因为要维护整个连通块的性质. 最后的难点在于, ...

随机推荐

  1. switch条件变量的取值类型

    switch条件变量的取值类型主要有以下六种: 1)JDK1.5(不含JDK1.5)之前只能是byte.short.int.char类型,不能是float.double.long.boolean类型. ...

  2. springBoot 静态变量@value取不到值

    在工具类中给静态变量初始化值,使用了springBoot的@Value注解,但是没有赋值成功,得到的是null @Value("${jdbc.url}")private stati ...

  3. Python list和tuple的相互转换?

    list转为tuple: temp_list = [1,2,3,4,5] 将temp_list进行强制转换:tuple(temp_list) 查看是否转换成功:print type(temp_list ...

  4. PY 个板子计划【雾

    各类板子计划 A+B √ 放个鬼的链接[雾 欧拉筛 √ https://www.cnblogs.com/Judge/p/11690114.html 树状数组 √ 惨痛的教训,以后咱打数据结构的时候绝对 ...

  5. 表单提交 multipart/form-data 和 x-www-form-urlencoded的区别

    表单提交表单有两种提交方式,POST和GET.通常我们会使用POST方式,一是因为形式上的安全 :二是可以上传文件. 我之前经常忽略掉表单的编码类型,觉得它特别长比较难记,而且不设置也似乎不影响什么. ...

  6. spring服务器接收参数格式

    注:@RequestParam 或@RequestBody等注解是否添加有什么区别 不加:参数可有可无,无参数时为null,但当参数类型是 数字基本类型(int.double)时会报错: 加上@Req ...

  7. NSURLSession断点下载

    #import <Foundation/Foundation.h> @class XHDownLoadManager; #pragma mark - delegate Method @pr ...

  8. django基础篇04-自定义simple_tag和fitler

    自定义simple_tag app目录下创建templatetags目录 templatetags目录下创建xxpp.py 创建template对象register,注意变量名必须为register ...

  9. ERROR: Unable to clean up existing run directory

    Project Navigator - Launching PlanAhead gives: ERROR: Unable to clean up existing run directory   De ...

  10. fpga配置方式 .jic固化为ps模式

    FPGA不同下载方式的区别[扫盲]以及如何利用AS模式固化程序(转载)     主动配置方式(AS)和被动配置方式(PS)和最常用的(JTAG)配置方式: AS由FPGA器件引导配置操作过程,它控制着 ...