bzoj 3308 九月的咖啡店
题目大意:
求若干个<=n的数 两两互质 使和最大 求这个最大的和
思路:
显然,得到两个结论
1 最终的所有数都只能分解为两个质因数
2 这两个质因数 一个<根号n 一个>根号n
于是可以建立二分图,按照数值是否大于根号n分为两个集合
把每个点不大于n的最大次幂加入答案
对于每两个所属集合不同的点,判断他们两个对答案的贡献是否大于两个独立对答案的贡献
如果是,就连边 跑最大费用流
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<queue> 8 #include<map> 9 #include<vector> 10 #define ll long long 11 #define inf 2139062143 12 #define MAXN 200100 13 #define MAXM 1000100 14 using namespace std; 15 inline int read() 16 { 17 int x=0,f=1;char ch=getchar(); 18 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 19 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 20 return x*f; 21 } 22 int n,ntp[MAXN],p[MAXN],tot,ans,q1[MAXN],q2[MAXN],r1,r2; 23 struct ZKW 24 { 25 int fst[MAXN],to[MAXM<<1],nxt[MAXM<<1],val[MAXM<<1],cos[MAXM<<1],cnt; 26 int dis[MAXN],s,t,vis[MAXN],res; 27 ZKW() {res=0,cnt=2;}//memset(fst,0xff,sizeof(fst));} 28 void add(int u,int v,int w,int c) {nxt[cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w,cos[cnt++]=c;} 29 int spfa() 30 { 31 memset(dis,127,sizeof(dis)); 32 queue<int> q; 33 dis[t]=0,vis[t]=1; 34 q.push(t); 35 while(!q.empty()) 36 { 37 int x=q.front();q.pop();vis[x]=0; 38 for(int i=fst[x];i;i=nxt[i]) 39 if(val[i^1]&&dis[to[i]]>dis[x]-cos[i]) 40 { 41 //cout<<x<<" "<<dis[x]<<" "<<to[i]<<endl; 42 dis[to[i]]=dis[x]-cos[i]; 43 if(!vis[to[i]]) {q.push(to[i]);vis[to[i]]=1;} 44 } 45 } 46 //memset(vis,0,sizeof(vis)); 47 //cout<<dis[s]<<endl<inf; 48 return dis[s]<0; 49 } 50 int dfs(int x,int a) 51 { 52 if(x==t||!a) {res+=dis[s]*a;return a;} 53 if(vis[x])return 0; 54 vis[x]=1; 55 //cout<<x<<endl; 56 int res=0,f; 57 for(int i=fst[x];i&&a;i=nxt[i]) 58 if(val[i]&&dis[to[i]]==dis[x]-cos[i]&&(f=dfs(to[i],min(a,val[i])))) 59 res+=f,val[i]-=f,val[i^1]+=f,a-=f; 60 vis[x]=0; 61 return res; 62 } 63 void solve() 64 { 65 while(spfa()) 66 { 67 vis[t] = 1; 68 while(vis[t]) 69 { 70 memset(vis,0,sizeof(vis)); 71 dfs(s,2147483647); 72 } 73 } 74 } 75 }Z; 76 void mem() 77 { 78 for(int i=2;i<=n;i++) 79 { 80 if(!ntp[i]) p[++tot]=i; 81 for(int j=1;p[j]*i<=n&&j<=tot;j++) 82 { 83 ntp[p[j]*i]=1; 84 if(i%p[j]==0) break; 85 } 86 }Z.s=0,Z.t=tot+1; 87 } 88 int calc(int n,int x) {int i=x;for(;i*x<=n;i*=x);return i;} 89 int main() 90 { 91 //freopen("kissatenn16.in","r",stdin); 92 n=read();mem();int h=sqrt(n),a,b,tmp,k; 93 for(int i=1;i<=tot;i++) 94 { 95 //cout<<i<<" "<<p[i]<<" "<<ans<<endl; 96 if(p[i]*2>n) {ans+=p[i];continue;} 97 if((ll)p[i]*p[i]<=n){Z.add(Z.s,i,1,0);Z.add(i,Z.s,0,0);ans+=calc(n,p[i]);q1[++r1]=i;} 98 else {Z.add(i,Z.t,1,0);Z.add(Z.t,i,0,0);ans+=p[i],q2[++r2]=i;} 99 } 100 for(int i=1;i<=r1;i++) 101 for(int j=1;j<=r2;j++) 102 { 103 a=p[q1[i]],b=p[q2[j]]; 104 if(p[q1[i]]*p[q2[j]]<=n) 105 { 106 tmp=calc(n/b,a)*b,k=calc(n,a)+b; 107 //cout<<a<<" "<<b<<" "<<tmp<<" "<<k<<endl; 108 if(tmp>k) {Z.add(q1[i],q2[j],1,k-tmp);Z.add(q2[j],q1[i],0,tmp-k);} 109 } 110 else break; 111 } 112 //cout<<ans<<endl; 113 Z.solve();printf("%d",ans-Z.res+1); 114 }