如果一条边的费用<0,那么不如不连
记得最后要加上1。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define maxn 200010 #define maxm 2000010 #define inf 1000000000 using namespace std; int head[maxn],to[maxm],c[maxm],next[maxm],len[maxm],p[maxm],fr[maxn],q[maxn],dis[maxn]; int prime[maxn]; bool vis[maxn]; int n,m,num,s,t,tot; int ans; void addedge(int x,int y,int z,int w) { num++;p[num]=x;to[num]=y;c[num]=z;len[num]=w;next[num]=head[x];head[x]=num; num++;p[num]=y;to[num]=x;c[num]=0;len[num]=-w;next[num]=head[y];head[y]=num; } bool spfa() { for (int i=s;i<=t;i++) dis[i]=-inf; memset(vis,0,sizeof(vis)); int l=0,r=1; q[1]=s;dis[s]=0;vis[s]=1; while (l!=r) { l++;if (l==maxn) l=0; int x=q[l]; for (int p=head[x];p;p=next[p]) if (c[p] && dis[x]+len[p]>dis[to[p]]) { dis[to[p]]=dis[x]+len[p]; fr[to[p]]=p; if (!vis[to[p]]) { r++;if (r==maxn) r=0; q[r]=to[p];vis[to[p]]=1; } } vis[x]=0; } if (dis[t]<0) return 0; else return 1; } void mcf() { int x=inf; for (int i=fr[t];i;i=fr[p[i]]) x=min(x,c[i]); for (int i=fr[t];i;i=fr[p[i]]) ans+=x*len[i],c[i]-=x,c[i^1]+=x; } void costflow() { while (spfa()) mcf(); } int cal(int n,int x) { long long t=x; while (t*x<=n) t*=x; return t; } int main() { scanf("%d",&n); for (int i=2;i<=n;i++) { if (!vis[i]) prime[++tot]=i; for (int j=1;j<=tot && prime[j]*i<=n;j++) { vis[i*prime[j]]=1; if (i%prime[j]==0) break; } } s=0,t=tot+1;num=1; int pos=0; for (int i=1;i<=tot;i++) { if (prime[i]>=n/2) {ans+=prime[i];continue;} if ((long long)prime[i]*prime[i]<=n) { addedge(s,i,1,0); ans+=cal(n,prime[i]); } else { if (!pos) pos=i; addedge(i,t,1,0); ans+=prime[i]; } } for (int i=1;i<pos;i++) for (int j=pos;j<=tot;j++) { if ((long long)prime[i]*prime[j]>n) break; int Cost=cal(n/prime[j],prime[i])*prime[j]-cal(n,prime[i])-prime[j]; if (Cost>0) addedge(i,j,1,Cost); } costflow(); printf("%d\n",ans+1); return 0; }