[雅礼4-7]T3 最小割/乱搞

考场上打暴力智障到用力的分解来判平衡。。。
我们发现相邻两片扇叶间隔相同组成的环是能保证平衡的,题目中说最多有两个素因子,所以素环最多只有两种(非素环可以用若干个素环拼起来)。所以我们要尽可能多的选环并且不能使同一片扇叶出现在两个环中。

考虑最小割:每个环看成一个点,源点向长度为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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值