1874 素数和最大


题目描述 Description

    有一天萌萌哒Sevenkplus在跟素数们玩>_<。。。他玩着玩着突然想到一个问题!就是这样的:
    从1到n这n个自然数中,选出一些数使得它们之间两两互质并且它们的和最大。
    当然Sevenkplus几分钟就秒杀了>_<。。。你也来试试吧~~~
    比如说n=10,那么选择{1,5,7,8,9}就行了,答案是30。

输入描述 Input Description

    一行一个整数n

输出描述 Output Description

    一行一个整数表示答案

样例输入 Sample Input

    3

样例输出 Sample Output

    6

数据范围及提示 Data Size & Hint

    【数据范围】

    测试点
    1..2:n<=100
    3..5:n<=1000
    6..10:n<=200000

     

    【卖萌向】

    素数可是很可爱的哦^_^

     

    【来源】

    我们都爱GYZ摸你赛 Problem C Hard

好题

一开始眼瞎+脑残,以为肯定是每一个素数都单独选它的最大次幂,全WA

好吧,看题解,果真是网络流+数论

先筛素数,把素数分成两类,一类是小于等于根号n的,这些可以自己乘多次,大于根号n的只能有一次幂

我们考虑这两类凑成一对一对的,如果凑成一对会更优,就连一条权值为增益的边(不过为什么不能小素数凑对呢?)

然后做二分图最大匹配

代码就别看了,因为建图,我的变量名已经乱了

  1 var
  2     flag:array[0..200010]of boolean;
  3     zhi,best:array[0..100000]of longint;
  4     first,next,last,val,cost,vis,db,link:array[0..200010]of longint;
  5     n,tot,jie,num,time:longint;
  6     ans:int64;
  7 
  8 procedure shai;
  9 var
 10     i,j:longint;
 11 begin
 12     for i:=2 to n do
 13       begin
 14         if flag[i]=false then
 15         begin
 16           inc(tot);
 17           zhi[tot]:=i;
 18         end;
 19         for j:=1 to tot do
 20           begin
 21             if i*zhi[j]<=n then flag[i*zhi[j]]:=true
 22             else break;
 23             if i mod zhi[j]=0 then break;
 24           end;
 25       end;
 26 end;
 27 
 28 procedure insert(x,y,z:longint);
 29 begin
 30     inc(num);
 31     last[num]:=y;
 32     next[num]:=first[x];
 33     first[x]:=num;
 34     val[num]:=z;
 35     if db[x]<z then db[x]:=z;
 36 end;
 37 
 38 procedure init;
 39 var
 40     i,j,k,s:longint;
 41 begin
 42     read(n);
 43     shai;
 44     ans:=1;
 45     for i:=1 to tot do
 46       begin
 47         k:=zhi[i];
 48         while k*zhi[i]<=n do
 49           k:=k*zhi[i];
 50         if k>zhi[i] then jie:=i;
 51         best[i]:=k;
 52         ans:=ans+k;
 53       end;
 54     for i:=1 to jie do
 55       for j:=jie+1 to tot do
 56         begin
 57           s:=zhi[j];
 58           while s*zhi[i]<=n do
 59             s:=s*zhi[i];
 60           if s>best[i]+best[j] then insert(i,j,s-best[i]-best[j]);
 61         end;
 62     for i:=1 to jie do
 63       insert(i,tot+i,0);
 64 end;
 65 
 66 function find(x:longint):boolean;
 67 var
 68     i:longint;
 69 begin
 70     vis[x]:=time;
 71     i:=first[x];
 72     while i<>0 do
 73       begin
 74         if (vis[last[i]]<>time)and(val[i]=db[x]+db[last[i]]) then
 75         begin
 76           vis[last[i]]:=time;
 77           if (link[last[i]]=0)or(find(link[last[i]])) then
 78           begin
 79             link[last[i]]:=x;
 80             cost[last[i]]:=val[i];
 81             exit(true);
 82           end;
 83         end;
 84         i:=next[i];
 85       end;
 86     exit(false);
 87 end;
 88 
 89 function km:int64;
 90 var
 91     i,j,k,d:longint;
 92 begin
 93     for i:=1 to jie do
 94       begin
 95         while true do
 96           begin
 97             inc(time);
 98             if find(i) then break;
 99             d:=maxlongint;
100             for k:=1 to jie do
101               if vis[k]=time then
102               begin
103                 j:=first[k];
104                 while j<>0 do
105                   begin
106                     if vis[last[j]]<>time then
107                     if d>db[k]+db[last[j]]-val[j] then d:=db[k]+db[last[j]]-val[j];
108                     j:=next[j];
109                   end;
110               end;
111             if d=maxlongint then break;
112             for j:=1 to jie do
113               if vis[j]=time then dec(db[j],d);
114             for j:=jie+1 to tot do
115               if vis[j]=time then inc(db[j],d);
116           end;
117       end;
118     km:=0;
119     for i:=jie+1 to tot do
120       inc(km,cost[i]);
121 end;
122 
123 begin
124     init;
125     write(km+ans);
126 end.
View Code
原文地址:https://www.cnblogs.com/Randolph87/p/3599938.html