1 条题解
-
0
抽象至极的一道题。 第一问想到用网络流;第二问拆分函数并最大流求,分得越细,即△的值越小,精度就越优秀,但复杂度就越劣;合理控制△的值,可以拿到一定的分数。
#include<bits/stdc++.h> #define x first #define y second using namespace std; typedef long long LL; const double eps=1e-8; const int N=1100,M=1100,INF=0x3f3f3f3f; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();} while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int cnt=1,head[N+M]; struct edge{int from,to,next; double val;}e[N*M<<1]; inline void add(int f,int t,double v) {e[++cnt]={f,t,head[f],v};head[f]=cnt;/*if(v)printf("%d %d %.1lf\n",f,t,(v && v<=10)? v:0);*/} inline LL gcd(LL a,LL b) {while(b){a%=b; a^=b; b^=a; a^=b;}return a;} inline void initiator() {memset(head,0,sizeof head); cnt=1;} struct frac //val=x/y { LL x,y; frac(){x=0; y=1;} frac(LL a,LL b=1):x(a),y(b) { LL g=gcd(a,b); x/=g; y/=g; } inline double value(){return (double)x/y;} }; typedef pair<frac,frac> point; struct line{frac k,b;}; //y=kx+b inline frac simplify(frac a) { if(!a.x) return frac(0,1); if(a.y<0) a.x=-a.x,a.y=-a.y; LL g=gcd(abs(a.x),a.y); } inline frac simplify(LL a,LL b){return simplify(frac(a,b));} inline frac operator+(frac a,frac b){return simplify(a.x*b.y+a.y*b.x,a.y*b.y);} inline frac operator-(frac a,frac b){return simplify(a.x*b.y-a.y*b.x,a.y*b.y);} inline frac operator*(frac a,frac b){return simplify(a.x*b.x,a.y*b.y);} inline frac operator/(frac a,frac b){return simplify(a.x*b.y,a.y*b.x);} inline bool operator==(frac a,frac b){return a.x==b.x && a.y==b.y;} inline bool operator==(line a,line b){return a.k==b.k && a.b==b.b;} inline void print(frac a){printf("%lld/%lld\n",a.x,a.y);} int n,m,a[N],b[N],c[N],d[M],dep[N+M],now[N+M],s=0,t; bool graph[N][M]; inline bool bfs() { memset(dep,0,sizeof dep); queue<int> q; dep[s]=1; q.push(s); now[s]=head[s]; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].next) if(e[i].val>0) { int v=e[i].to; if(dep[v]) continue; dep[v]=dep[u]+1; now[v]=head[v]; if(v==t) return 1; q.push(v); } } } double dinic(int u,double flow) { if(u==t) return flow; double last=flow; for(int &i=now[u];i;i=e[i].next) if(e[i].val>0) { int v=e[i].to; if(dep[v]!=dep[u]+1) continue; double k=dinic(v,min(last,e[i].val)); if(!k) dep[v]=-1; last-=k; e[i].val-=k; e[i^1].val+=k; if(!last) break; } } line solve(double x) { initiator(); for(int i=1;i<=n;++i) if(b[i]<x) { double lim=a[i]? min((x-b[i])/2/a[i],(double)c[i]):c[i]; add(s,i,lim); add(i,s,0); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(graph[i][j]) add(i,n+j,1e18),add(n+j,i,0); for(int i=1;i<=m;++i) add(n+i,t,d[i]),add(t,n+i,0); while(bfs()) dinic(s,1e18); line res; for(int i=2;i<=cnt;i+=2) if(!dep[e[i].to]) //注意这里不能直接判流量(double 永远的痛) { if(e[i].from==s) { int u=e[i].to; if(a[u] && x<2*a[u]*c[u]+b[u]) { res.k=res.k+(frac)1/2/a[u]; res.b=res.b-(frac)b[u]/2/a[u]; // printf("for edge %d->%d k+=%d/%d\n",s,e[i].to,((frac)1/2/a[u]).x,((frac)1/2/a[u]).y); } else res.b=res.b+c[u];//,printf("for edge %d->%d b+=%d\n",s,e[i].to,c[u]); } else if(e[i].to==t && dep[e[i].from]) //说明这条边是流量限制 res.b=res.b+d[e[i].from-n];//,printf("for edge %d->%d b+=%d\n",e[i].from,t,d[e[i].from-n]); } // printf("res.k=%d/%d\n",res.k.x,res.k.y); } vector<point> v; void solve(line l,line r) { // printf("solving (%d/%d)x+(%d/%d) ~ (%d/%d)x+(%d/%d)\n",l.k.x,l.k.y,l.b.x,l.b.y,r.k.x,r.k.y,r.b.x,r.b.y); if(l.k==r.k) return; frac x=(r.b-l.b)/(l.k-r.k); point p=make_pair(x,x*l.k+l.b); line midl=solve(p.x.value()-eps); line midr=solve(p.x.value()+eps); if(midr==r) {/*printf("pushing (%d/%d,%d/%d)\n",p.x.x,p.x.y,p.y.x,p.y.y);*/ v.push_back(p); return;} else solve(l,midl),solve(midr,r); } int main() { // freopen("mincost10.in","r",stdin); // freopen("mincost10.out","w",stdout); n=read(); m=read(); t=n+m+1; for(int i=1;i<=n;++i) a[i]=read(),b[i]=read(),c[i]=read(); for(int i=1;i<=m;++i) d[i]=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) graph[i][j]=read(); line r=solve(1e9); frac ans; assert(r.b.y==1); v.push_back(make_pair(frac(),frac())); for(int i=1;i<=3;++i) { line left=solve(i-1+eps); line right=solve(i-eps); v.push_back(make_pair(frac(i-1),left.k*(i-1)+left.b)); solve(left,right); v.push_back(make_pair(frac(i),right.k*i+right.b)); } line now=solve(3+eps); v.push_back(make_pair(frac(3),now.k*3+now.b)); solve(solve(3+eps),r); for(unsigned i=1;i<v.size();++i) { frac now=(v[i].x+v[i-1].x)*(v[i].y-v[i-1].y)/2; // printf("now ans+=%d/%d\n",now.x,now.y); ans=ans+now; } }
- 1
信息
- ID
- 196
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 2
- 上传者