考场上打暴力智障到用力的分解来判平衡。。。
我们发现相邻两片扇叶间隔相同组成的环是能保证平衡的,题目中说最多有两个素因子,所以素环最多只有两种(非素环可以用若干个素环拼起来)。所以我们要尽可能多的选环并且不能使同一片扇叶出现在两个环中。
考虑最小割:每个环看成一个点,源点向长度为p1的环连一个容量为p1的边,长度为p2的环向汇点连一个容量为p2的边;如果某个扇叶坏了,把它所在的环与源汇点的边断掉;如果某两个环有冲突,则连一条容量为INF的边,这样有冲突的两条边就只能留一条。
某雅礼神犇的O(n)算法:构造n/p1/p2个p1*p2的矩阵,每个矩阵的左上角分别为1~n/p1/p2,然后p1方向每格+n/p1,p2方向每格+n/p2(都要mod n)。这样每一个矩阵贪心选择行或列中更多的那个,注意特判素数。
方法二代码:
type
node=record
c,x,y:longint;
end;
var
n,k,num,i,j,l,p1,p2,x,g,f,s,t,ans:longint;
p:array[0..20000]of longint;
flag,brk,chs:array[0..20100]of boolean;
jz:array[0..200,0..200]of longint;
b:boolean;
procedure getpri;
var
i,j:longint;
begin
for i:=2 to 100 do
begin
if flag[i]=true then begin inc(num); p[num]:=i end;
j:=1;
while (p[j]*i<=100)and(j<=num) do
begin
flag[p[j]*i]:=false;
if i mod p[j]=0 then break;
inc(j);
end;
end;
end;
function max(x,y:longint):longint;
begin
if x>y then exit(x)
else exit(y);
end;
begin
readln(n,k);
fillchar(flag,sizeof(flag),true);
num:=0;
getpri;
p1:=1;
p2:=1;
for i:=1 to num do
if n mod p[i]=0 then
begin
if p1=1 then p1:=p[i]
else begin p2:=p[i]; break; end;
end;
if p2=1 then begin t:=p1; p1:=p2; p2:=t; end;
for i:=1 to k do
begin
read(x);
brk[x]:=true;
end;
for l:=1 to n div p1 div p2 do
begin
s:=0;
t:=0;
jz[1,1]:=l;
for i:=2 to p1 do
jz[1,i]:=(jz[1,i-1]+n div p1-1)mod n+1;
for i:=2 to p2 do
for j:=1 to p1 do
jz[i,j]:=(jz[i-1,j]+n div p2-1)mod n+1;
for i:=1 to p2 do
begin
b:=true;
for j:=1 to p1 do
if brk[jz[i,j]]=true then begin b:=false; break; end;
if b=true then inc(s);
end;
for j:=1 to p1 do
begin
b:=true;
for i:=1 to p2 do
if brk[jz[i,j]]=true then begin b:=false; break; end;
if b=true then inc(t);
end;
if (s*p1>t*p2)and(p1>1) then
for i:=1 to p2 do
begin
b:=true;
for j:=1 to p1 do
if brk[jz[i,j]]=true then begin b:=false; break; end;
if b=true then
for j:=1 to p1 do
chs[jz[i,j]]:=true;
end
else if (p2>1) then
for j:=1 to p1 do
begin
b:=true;
for i:=1 to p2 do
if brk[jz[i,j]]=true then begin b:=false; break; end;
if b=true then
for i:=1 to p2 do
chs[jz[i,j]]:=true;
end;
end;
for i:=1 to n do
if (chs[i]=false)and(brk[i]=false) then inc(ans);
if ans>=n-k then writeln(-1)
else
begin
writeln(ans);
for i:=1 to n do
if (chs[i]=false)and(brk[i]=false) then write(i,' ');
end;
end.