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 }

浙公网安备 33010602011771号