codevs1874 素数和最大 二分图最大权匹配。

费用流第一题~

  思路不想写了,贴一下前辈们写的吧~

  令大于sqrt(N)的素数为大素数,反之为小素数,可以发现大素数的数量非常多,并且一个选的数里只能有一个大素数因子。

  那么由于大素数只能跟小素数配在一起,同时小素数又很少,所以如果2个小素数跟大素数配,我们把这两个小素数拿出来,肯定能找到另外两个空闲着的大素数,从而凑出更多的大数。

  所以可以发现选取的数要么是一个素数的最高次幂,要么是一个大素数配上一个小素数的一定次幂。

  那么就转化成了二分图最大权匹配的问题,使用费用流解决就行了。

其实搞这题的时间有点久,主要是练习时间不够,和一开始思路没走对,不过成就感还是挺强的,怼一道题4天的感觉还是挺好的。

同时,素数其实很离散的,我就开了个map来维护节点编号,剩了不少空间,

时间上,我们发现即便是最大数据200000,开了根号后小素数也不过一千,边也很少,跑的挺快的。

代码还是粘吧~挺长挺丑的。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<stack>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<set>
  8 #include<cstring>
  9 #include<cstdlib>
 10 #include<map>
 11 using namespace std;
 12 
 13 const int maxn = 200400;
 14 const int maxm = 40000;
 15 map<int,int> ID;
 16 int ID_num;
 17 int n;
 18 int N[maxn];
 19 vector<int> S,B;
 20 typedef long long LL;
 21 
 22 struct Edge{
 23     int from,to,cap,flow,cost;
 24     Edge(int from,int to,int cap,int flow,int cost):
 25         from(from),to(to),cap(cap),flow(flow),cost(cost)
 26         {}
 27     
 28 };
 29 
 30 int get_ID(int n)
 31 {
 32     if(ID.count(n)) return ID[n];
 33     else{
 34         ID_num ++;
 35         ID[n] = ID_num;
 36         return ID_num;
 37     }    
 38 }
 39 
 40 int G(int a)
 41 {
 42     if(a == 1) return a;
 43     int k = a;
 44     while(k <= n) k*=a;
 45     return k/a;
 46 }
 47 
 48 
 49 void Sha()
 50 {
 51     int m = sqrt(n);
 52     for(int i = 2;i <= n;i++ )
 53         if(!N[i])
 54         for(int j = i*2;j <= n;j+=i)
 55             N[j] = 1;
 56     for(int i = 1;i <= m;i++)
 57         if(!N[i]) S.push_back(i);
 58     for(int j = m+1;j <= n;j++)
 59         if(!N[j]) B.push_back(j);
 60 }
 61 
 62 struct MCMF
 63 {
 64     static const int INF = 1<<29;
 65     int s,t;
 66     vector<int> G[maxm];
 67     vector<Edge> edges;
 68     int d[maxn];
 69     int p[maxm];
 70     int a[maxm];
 71     int inq[maxm];
 72 
 73     void AddEdge(int from,int to,int cap,int cost)
 74     {
 75         edges.push_back(Edge(from,to,cap,0,cost));
 76         edges.push_back(Edge(to,from,0,0,-cost));
 77         int m = edges.size();
 78         G[from].push_back(m-2);
 79         G[to].push_back(m-1);
 80     }
 81     
 82     bool BF(int s,int t,int& flow,LL& cost)
 83     {
 84         memset(a,0x7f,sizeof(a));
 85         memset(d,0x7f,sizeof(d));
 86         memset(inq,0,sizeof(inq));            
 87         queue<int> Q;
 88         d[s]  = 0;
 89         a[s] = INF;
 90         inq[s] = 1;
 91         Q.push(s);        
 92         while(!Q.empty())
 93         {
 94             int u = Q.front();Q.pop();
 95             inq[u] = 0;
 96             for(int i = 0;i < G[u].size();i++)
 97             {
 98                 Edge& e = edges[G[u][i]];
 99                 if(e.cap > e.flow&&d[e.to] > d[u]+e.cost)
100                 {
101                     a[e.to] = min(a[u],e.cap-e.flow);
102                     d[e.to] = d[u]+e.cost;
103                     p[e.to] = G[u][i];
104                     if(!inq[e.to]){Q.push(e.to);inq[e.to] = 1;}
105                 }                
106             }        
107         }
108         if(d[t] == d[t+1]) return false;
109         flow += a[t];
110         cost += a[t]*d[t];
111         for(int u = t;u != s;u = edges[p[u]].from)
112         {
113             edges[p[u]].flow += a[t];
114             edges[p[u]^1].flow -= a[t];
115         }
116         return true;
117     }
118     
119     LL Mincost(int s,int t)
120     {
121         this -> s = s; this-> t = t;
122         int flow = 0;LL cost =0;
123         LL ans = 0;
124         while(BF(s,t,flow,cost)){
125             ans = min(ans,cost);
126         }
127         return ans;
128     }
129 }solver;
130 
131 
132 void build()
133 {
134     for(int i = 0;i < S.size();i++)
135         solver.AddEdge(get_ID(0),get_ID(S[i]),1,0);
136     for(int i = 0;i < S.size();i++)
137         for(int j = 0;j < B.size();j++)
138         {
139             int k = S[i]*B[j];
140             if(k > n) break;
141             while(S[i] != 1&&k <= n) k*=S[i];
142             k /= S[i];
143             if(k > G(S[i])+B[j])
144                 solver.AddEdge(get_ID(S[i]),get_ID(B[j]),1,-(k-G(S[i])-B[j]));    
145         }
146     for(int i = 0;i < B.size();i++)
147         solver.AddEdge(get_ID(B[i]),get_ID(n+1),1,0);    
148 }
149 int main()
150 {
151     scanf("%d",&n);
152     Sha();
153     LL tot = 0;
154     for(int i = 0;i < S.size();i++)    
155         tot+= G(S[i]);
156     for(int i = 0;i < B.size();i++)
157         tot+= B[i];
158     build();
159     tot -= solver.Mincost(get_ID(0),get_ID(n+1));    
160     cout<<tot<<endl;
161     return 0;
162 }
素数和最大

 

posted @ 2017-03-28 14:15  rsqppp  阅读(176)  评论(0)    收藏  举报