省选模拟13
T1
费用流,拆点,把点按奇偶分类
偶数的直接拆成 \(\frac{a_i}{2}\) ,奇数的也一样,然后枚举哪一边的流量多,再给他加上就行
Code
#include
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,ans=inf,p,U,S,T;
int a[60],c[60][60],trans[60];
int L[60],R[60];
namespace FLOW{
int COST;
int dis[1010],q[1010],h,t;
int head[1010],ver[6000],to[6000],edge[6000],cost[6000],tot=1;
bool inq[1010],vis[1010];
inline void add(int x,int y,int z,int w){
ver[++tot]=y;edge[tot]=z;cost[tot]= w;to[tot]=head[x];head[x]=tot;
ver[++tot]=x;edge[tot]=0;cost[tot]=-w;to[tot]=head[y];head[y]=tot;
}
inline bool spfa(){
for(int i=1;i<=T;i++) dis[i]=inf,inq[i]=0;
dis[S]=0,q[h=t=1]=S,inq[S]=1;memset(vis,0,sizeof(vis));
while(h<=t){
int x=q[h++];inq[x]=0;
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(dis[y]>dis[x]+cost[i]){
dis[y]=dis[x]+cost[i];
if(!inq[y]) q[++t]=y,inq[y]=1;
}
}
}
return dis[T]!=inf;
}
int dfs(int x,int in){
if(x==T) return in;
int res=in,go;vis[x]=1;
for(int i=head[x];i;i=to[i]) if(edge[i]){
int y=ver[i];
if(vis[y]) continue;
if(dis[y]==dis[x]+cost[i]){
go=dfs(y,min(res,edge[i]));
res-=go,edge[i]-=go,edge[i^1]+=go;
COST+=go*cost[i];
}
if(!res) break;
}
return in-res;
}
inline void clear(){for(int i=1;i<=T;i++) head[i]=0;tot=1;COST=0;}
inline int MinCost(){while(spfa()) dfs(S,inf);return COST;}
}using FLOW::add;
signed main(){
#ifdef LOCAL
freopen("in","r",stdin);
freopen("out","w",stdout);
#endif
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
n=read();S=n*2+1,T=n*2+2;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j]=read();
for(int i=1;i<=n;i++) if(a[i]&1) trans[++p]=i;if(p&1) puts("-1"),exit(0);
U=(1<>(i-1)&1) L[trans[i]]++;else R[trans[i]]++;
FLOW::clear();
for(int i=1;i<=n;i++) add(S,i,L[i],0),add(i+n,T,R[i],0);
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) add(i,j+n,inf,c[i][j]);
ans=min(ans,FLOW::MinCost());
}
printf("%lld\n",ans);
return 0;
}
T2
对于每个节点都维护一些线段,只用记录他的左右端点
合并的时候考虑哪一条线段作为第一条线段,再用状压 \(dp\) 出以这个线段为左端点时的最小的右端点
注意把劣的去掉,同时在状压的过程中记录合并的顺序
Code
#include
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n;
struct seg{
int l,r,id;
inline bool operator<(const seg &b)const{return (l==b.l)?rmp;
vectorg[100010],ans[100010];
vectorvec[100010],tmp;
int f[100010],ff[100010],son[100010],id[100010];
void dfs1(int x){
if(!g[x].size()) return ;int p=0;
for(auto y:g[x]) dfs1(y),son[y]=++p;
if(g[x].size()==1) return swap(vec[x],vec[g[x][0]]),void();
int U=(1<<(g[x].size()-1))-1;
mp.clear();tmp.clear();seg t;
for(int i=0;i>(j-1))&1)){
ed=vec[id[j]].size();
pos=lower_bound(vec[id[j]].begin(),vec[id[j]].end(),t)-vec[id[j]].begin();
if(pos!=ed&&vec[id[j]][pos].r
T3
考虑 \(O(n^2)\) 的暴力,对每个点都把他能直接传染到的点和他连边
然后再用 \(tarjan\) 缩点,最后剩下几个没有入度的点,答案就是几
考虑用点分治来优化这个过程
对于每个分治中心,把所有的路径长度都找出来
对每个长度都分别建立虚点,由长向短依次连边
再看每个点,由长度大于等于他的第一个虚点连边,再由他向他能传染到的跨过分治中心的最远的点连边
这里只考虑跨过分治中心的,没有跨过的会在其他地方考虑到
最后再用 \(tarjan\) 缩点,找到没有入度的点就行
Code
#include
#define int long long
#define rint signed
#define inf 0x3f3f3f3f
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int n,ans,deg[4300010],r[300010],N;
rint head[300010],ver[600010],to[600010],tot;
int edge[600010];
rint dfn[4300010],low[4300010],clo,mn[4300010];
rint scc[4300010],col,stk[4300010],p;
int S,rt,mxdis;
rint siz[4300010],mx[4300010],id[4300010];
bool vis[4300010];
vectorg[4100000],gg[3420000];
vectorvec;
queueq;
inline void add(rint x,rint y,rint z){ver[++tot]=y;edge[tot]=z;to[tot]=head[x];head[x]=tot;}
void tarjan(int x){
dfn[x]=low[x]=++clo;vis[x]=1;stk[++p]=x;
for(auto y:g[x]){
if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
rint k;col++;mn[col]=N+1;
do{k=stk[p--];scc[k]=col;vis[k]=0;mn[col]=min(mn[col],k);}while(k!=x);
}
}
void getrt(int x,int fa){
siz[x]=1,mx[x]=0;
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa||vis[y]) continue;
getrt(y,x);siz[x]+=siz[y];mx[x]=max(mx[x],siz[y]);
}
mx[x]=max(mx[x],(rint)S-siz[x]);
if(mx[x]=0){
pos=upper_bound(vec.begin(),vec.end(),range)-vec.begin();
if(pos) g[x].emplace_back(id[pos-1]);
}
for(rint i=head[x];i;i=to[i]){
int y=ver[i];
if(y==fa||vis[y]) continue;
dfs2(y,x,dis+edge[i]);
}
}
inline void calc(int x){
vec.clear();mxdis=-1;getdis(x,0,0);
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(rint i=0;i