題意:有n個二次函數$y=a_ix^2+b_ix+c_i$($a_i,b_i,c_i$是整數),第i個函數要求x的取值在$[l_i,r_i]$之間且爲整數。你須要肯定每一個函數的x的取值,使得全部函數的函數值之和最大。還有m個限制,每條限制形如$u,v,d$,表示$x_u\le x_v+d$。求最大函數值之和。ios
$n\le 50,m\le 100,-100\le l_i\le r_i\le 100$函數
題解:傻逼了連切糕都忘了。spa
對於一個方程,咱們把它的全部可能取值按照x從小到大串成一串,首尾分別與S和T相連,其中第i個點和第i+1個點的邊的容量爲當$x=l+i-1$時的函數值(因爲可能存在負數,咱們給每條邊的權值都加上一個大數,最後再把這個大數減去)。對於限制u,v,d,咱們從u中全部表明$x_u=i$的點向v中表明$x_v=i-d$的點連一條容量inf的邊,便完成了限制。blog
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const ll big=1ll<<30; const ll inf=1ll<<50; int n,m,tot,S,T,cnt; ll ans; int L[60],R[60],to[200010],nxt[200010],head[12000],d[12000]; int p[60][210]; ll val[200010],A[60],B[60],C[60]; queue<int> q; inline void add(int a,int b,ll c) { to[cnt]=b,val[cnt]=c,nxt[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,nxt[cnt]=head[b],head[b]=cnt++; } ll dfs(int x,ll mf) { if(x==T) return mf; int i; ll temp=mf,k; for(i=head[x];i!=-1;i=nxt[i]) if(val[i]&&d[to[i]]==d[x]+1) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=-1; temp-=k,val[i]-=k,val[i^1]+=k; if(!temp) break; } return mf-temp; } inline int bfs() { while(!q.empty()) q.pop(); int i,u; memset(d,0,sizeof(d)); q.push(S),d[S]=1; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=nxt[i]) if(val[i]&&!d[to[i]]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } return 0; } int main() { //freopen("cf434D.in","r",stdin); scanf("%d%d",&n,&m); S=0,T=tot=1; int i,j,a,b,c; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) scanf("%lld%lld%lld",&A[i],&B[i],&C[i]); for(i=1;i<=n;i++) { scanf("%d%d",&L[i],&R[i]); add(S,tot+1,inf); for(j=L[i];j<=R[i];j++) { p[i][j-L[i]]=++tot; add(tot,tot+1,big-(A[i]*j*j+B[i]*j+C[i])); } p[i][R[i]-L[i]+1]=++tot; add(tot,T,inf); } for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); for(j=max(L[b],L[a]-c);j<=min(R[b],R[a]-c)+1;j++) { add(p[a][j+c-L[a]],p[b][j-L[b]],inf); } } while(bfs()) ans+=dfs(S,inf); printf("%lld",big*n-ans); return 0; }