积累一些题
luogu p2472
直接最大流,拆点限制经过次数即可
#include <bits/stdc++.h> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=r;i>=l;--i) using namespace std; typedef long long s64; const int M=2e3+5; int n,m,d; char s[25]; int a[25][25]; int S,T,dep[M],e_size,head[M]; struct edge { int v,w,nxt; }e[M*10]; void e_add(int u,int v,int w) { e[++e_size]=(edge){v,w,head[u]}; head[u]=e_size; } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } int Dfs(int x,int cp) { if(x==T) return cp; int las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w&&las) { q=Dfs(v,min(las,e[i].w)); if(!q) {dep[v]=0;continue;} e[i].w-=q,las-=q,e[i^1].w+=q; if(!las) break; } } return cp-las; } int main() { //freopen("a.in","r",stdin); scanf("%d%d%d",&n,&m,&d); rep(i,1,n) { scanf("%s",s+1); rep(j,1,m) a[i][j]=s[j]-'0'; } S=M-2,T=M-1; int ans=0; e_size=1; rep(i,1,n) { scanf("%s",s+1); rep(j,1,m) if(s[j]=='L') { ++ans; int x=S,y=i*m-m+j; e_add(x,y,1),e_add(y,x,0); } } rep(i,1,n) rep(j,1,m) if(a[i][j]) { int x=i*m-m+j,y=x+n*m; e_add(x,y,a[i][j]),e_add(y,x,0); } rep(i,1,n) rep(j,1,m) if(a[i][j]) { bool vis=0; int u=i*m-m+j+n*m; rep(x,i-d,i+d) rep(y,j-d,j+d) { if((x-i)*(x-i)+(y-j)*(y-j)>d*d) continue; if(x<1||y<1||x>n||y>m) { if(!vis) vis=1,e_add(u,T,1e5),e_add(T,u,0); } else if(a[x][y]) { int v=x*m-m+y; //cout<<u<<" "<<v<<endl; e_add(u,v,1e5),e_add(v,u,0); } } } while (Bfs()) ans-=Dfs(S,1e5); cout<<ans<<endl; }
luogu p3305
显然二分+最大流
#include <bits/stdc++.h> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=r;i>=l;--i) using namespace std; typedef long long s64; const int M=1e3+5; const double eps=1e-10; int n,m; double p,a[M*10]; int e_size,head[M],dep[M]; struct edge { int v; double w; int nxt; }e[M*10]; void e_add(int u,int v,double w) { e[++e_size]=(edge) {v,w,head[u]}; head[u]=e_size; a[e_size]=w; } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[1]=1; q.push(1); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w>eps) { dep[v]=dep[r]+1; q.push(v); if(v==n) return 1; } } } return 0; } double Dfs(int x,double cp) { if(x==n) return cp; double las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w>eps&&las>eps) { q=Dfs(v,min(las,e[i].w)); if(q<eps) {dep[v]=0;continue;} e[i].w-=q,las-=q,e[i^1].w+=q; } } return cp-las; } double calc(double Min) { rep(i,2,e_size) e[i].w=min(Min,a[i]); double ans=0; while (Bfs()) ans+=Dfs(1,1e9); return ans; } int main() { //freopen("a.in","r",stdin); scanf("%d%d%lf",&n,&m,&p); e_size=1; rep(i,1,m) { int x,y; double c; scanf("%d%d%lf",&x,&y,&c); e_add(x,y,c),e_add(y,x,0); } double ans=0; while (Bfs()) ans+=Dfs(1,1e9); printf("%.0f\n",ans); double l=0,r=5e4,mid; while (l+eps<r) { mid=(l+r)/2; if(calc(mid)+eps>ans) r=mid; else l=mid; } printf("%.4f\n",r*p); }
luogu p5038
偶数想出来了,显然可以二分,然后直接黑白染色就行了
奇数可以直接解出答案check。。。
#include <bits/stdc++.h> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=r;i>=l;--i) using namespace std; typedef long long s64; const int M=3e3+5; int n,m; int S,T,a[55][55]; int e_size,head[M],dep[M]; int x_[4]={0,0,-1,1},y_[4]={1,-1,0,0}; struct edge { int u,v; s64 w; int nxt; }e[M*10]; void e_add(int u,int v,s64 w) { e[++e_size]=(edge){u,v,w,head[u]}; head[u]=e_size; } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } s64 Dfs(int x,s64 cp) { if(x==T) return cp; s64 las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w&&las) { q=Dfs(v,min(e[i].w,las)); if(!q) {dep[v]=0;continue;} e[i].w-=q,e[i^1].w+=q,las-=q; } } return cp-las; } bool check(s64 val) { e_size=1; memset(head,0,sizeof(head)); s64 tot=0; rep(i,1,n) rep(j,1,m) { int x=i*m-m+j; tot+=val-a[i][j]; if(i+j&1) e_add(S,x,val-a[i][j]),e_add(x,S,0); else e_add(x,T,val-a[i][j]),e_add(T,x,0); } rep(i,1,n) rep(j,1,m) if(i+j&1) rep(k,0,3) { int x=i+x_[k],y=j+y_[k]; int u=i*m-m+j,v=x*m-m+y; if(!(x<1||y<1||x>n||y>m)) e_add(u,v,1e18),e_add(v,u,0); } s64 sum=0; while (Bfs()) sum+=Dfs(S,1e18); return sum==tot/2; } int main() { //freopen("a.in","r",stdin); int test_; scanf("%d",&test_); while (test_--) { S=M-2,T=S+1; int mx=0; s64 cnt[2]={0}; s64 sum[2]={0}; scanf("%d%d",&n,&m); rep(i,1,n) rep(j,1,m) { scanf("%d",a[i]+j); mx=max(mx,a[i][j]); ++cnt[i+j&1],sum[i+j&1]+=a[i][j]; } if(cnt[0]!=cnt[1]) { s64 ans=(sum[0]-sum[1])/(cnt[0]-cnt[1]); if(ans<mx||!check(ans)) puts("-1"); else printf("%lld\n",ans*n*m-sum[0]-sum[1]>>1); } else { if(sum[0]!=sum[1]) puts("-1"); else { s64 l=mx,r=1e16,mid,ans=-1; while (l<=r) { mid=l+r>>1; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } if(ans==-1) puts("-1"); else printf("%lld\n",ans*n*m-sum[0]-sum[1]>>1); } } } }
luogu p4542
一个裸的上下界可行流
注意最短路用floyd保证经过的点都小于等于k
#include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=l;i>=r;--i) using namespace std; typedef long long s64; const int M=3e2+10; int n,m,K; int S,T,a[M][M]; int dis[M],inq_[M],pre[M]; int e_size,head[M]; struct edge{ int u,v,w,c,nxt; }e[M*M*10]; void e_add(int u,int v,int w,int c) { e[++e_size]=(edge){u,v,w,c,head[u]}; head[u]=e_size; } void insert(int u,int v,int w,int c) { e_add(u,v,w,c),e_add(v,u,0,-c); } void spfa() { queue <int> q; memset(inq_,0,sizeof(inq_)); memset(dis,0x7f,sizeof(dis)); dis[S]=0; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); inq_[r]=0; for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(e[i].w&&dis[v]>dis[r]+e[i].c) { pre[v]=i; dis[v]=dis[r]+e[i].c; if(!inq_[v]) q.push(v),inq_[v]=1; } } } } int feiyong() { int ans=0; while (spfa(),dis[T]<2e9) { int t=2e9; for(int i=pre[T];i;i=pre[e[i].u]) t=min(t,e[i].w); //cout<<t<<endl; ans+=t*dis[T]; for(int i=pre[T];i;i=pre[e[i].u]) e[i].w-=t,e[i^1].w+=t; } return ans; } int main() { //freopen("a.txt","r",stdin); scanf("%d%d%d",&n,&m,&K); ++n; memset(a,0x3f,sizeof(a)); rep(i,1,n) a[i][i]=0; rep(i,1,m) { int x,y,z; scanf("%d%d%d",&x,&y,&z); ++x,++y; if(z<a[x][y]) a[x][y]=a[y][x]=z; } e_size=1; rep(u,1,n) { rep(i,1,n) rep(j,1,n) a[i][j]=min(a[i][j],a[i][u]+a[u][j]); if(u>1) insert(2*n+3,u,1e9,a[1][u]); rep(i,2,u-1) insert(i+n,u,1e9,a[i][u]); } insert(n+1,1,1e9,0); insert(1,2*n+3,K,0); rep(i,2,n) { insert(i,i+n,1e9,0); insert(i+n,n+1,1e9,0); } S=2*n+1,T=S+1; rep(i,2,n) insert(S,i+n,1,0),insert(i,T,1,0); printf("%d\n",feiyong()); }
luogu p2805
tarjan去掉不可能吃的plants之后裸的最大权闭合子图
#include <bits/stdc++.h> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=l;i>=r;--i) using namespace std; typedef long long s64; const int M=1e5+5; int n,m; int a[55][55]; bool not_[M]; int be[M],dfn[M],low[M],time_,size[M]; int S,T,e_size,head[M],dep[M]; stack <int> sta; vector <int> to[M]; struct edge { int v,w,nxt; }e[M*10]; void e_add(int u,int v,int w) { e[++e_size]=(edge){v,w,head[u]}; head[u]=e_size; } void insert(int u,int v,int w) { e_add(u,v,w),e_add(v,u,0); } void tarjan(int x) { dfn[x]=low[x]=++time_; sta.push(x); for(auto v:to[x]) { if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(!be[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { be[0]++; while(1) { ++size[be[0]]; int t=sta.top(); sta.pop(); be[t]=be[0]; if(x==t) break; } } } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); q.push(S); dep[S]=1; while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } int Dfs(int x,int cp) { if(x==T) return cp; int las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&las&&e[i].w) { q=Dfs(v,min(e[i].w,las)); if(!q) {dep[v]=0;continue;} las-=q,e[i].w-=q,e[i^1].w+=q; } } return cp-las; } int main() { //freopen("a.txt","r",stdin); scanf("%d%d",&n,&m); rep(i,1,n) rep(j,1,m) { scanf("%d",a[i]+j); int cnt,x,y; scanf("%d",&cnt); rep(k,1,cnt) { scanf("%d%d",&x,&y); ++x,++y; to[i*m-m+j].push_back(x*m-m+y); } if(j>1) to[i*m-m+j].push_back(i*m-m+j-1); } rep(i,1,n*m) if(!dfn[i]) tarjan(i); rep(i,1,n*m) if(size[be[i]]>1) not_[i]=1; rep(i,1,n*m) per(j,m-1,1) if(not_[i*m-m+j+1]) not_[i*m-m+j]=1; e_size=1; int ans=0; S=n*m+1,T=S+1; rep(i,1,n) rep(j,1,m) { int x=i*m-m+j; if(not_[x]) continue; for(auto v:to[x]) if(!not_[v]) insert(v,x,1e9); ans+=max(0,a[i][j]); if(a[i][j]>0) insert(S,x,a[i][j]); else insert(x,T,-a[i][j]); } while (Bfs()) ans-=Dfs(S,1e9); cout<<ans<<endl; return 0; }
luogu p3749
裸的最大权闭合子图
#include <queue> #include <cstdio> #include <cstring> #include <algorithm> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=l;i>=r;--i) using namespace std; typedef long long s64; const int M=1e2+5; const int N=1e4+5; const int inf=0x7fffffff; int n,m; int S,T; int a[M],b[M][M],id[M][M]; int e_size,dep[N],head[N]; struct edge{ int v,w,nxt; }e[N*10]; void e_add(int u,int v,int w) { e[++e_size]=(edge){v,w,head[u]}; head[u]=e_size; } void insert(int u,int v,int w) { e_add(u,v,w),e_add(v,u,0); } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } int Dfs(int x,int cp) { if(x==T) return cp; int las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w&&las) { q=Dfs(v,min(e[i].w,las)); if(!q) {dep[v]=0;continue;} las-=q,e[i].w-=q,e[i^1].w+=q; } } return cp-las; } int main() { //freopen("a.txt","r",stdin); //printf("%d\n",inf); scanf("%d%d",&n,&m); rep(i,1,n) scanf("%d",a+i); rep(i,1,n) rep(j,i,n) scanf("%d",b[i]+j),id[i][j]=++id[0][0]; rep(i,1,n) b[i][i]-=a[i]; int ans=0; e_size=1; S=id[n][n]+1001,T=S+1; rep(i,1,n) rep(j,i,n) { ans+=max(0,b[i][j]); if(i==j) { insert(id[i][j],a[i]+id[n][n],inf); b[i][j]>0?insert(S,id[i][j],b[i][j]):insert(id[i][j],T,-b[i][j]); } else { insert(id[i][j],id[i][j-1],inf); insert(id[i][j],id[i+1][j],inf); b[i][j]>0?insert(S,id[i][j],b[i][j]):insert(id[i][j],T,-b[i][j]); } } sort(a+1,a+n+1); a[0]=a[1]-1; rep(i,1,n) if(a[i]!=a[i-1]) insert(id[n][n]+a[i],T,m*a[i]*a[i]); while(Bfs()) ans-=Dfs(S,inf); printf("%d\n",ans); }
luogu p4126
需要仔细想一下条件
可能在:u,v不在一个scc内(即所有条件下都满流)
必须在:S和u在一个scc内,v和T在一个scc内(若不删这条边就可以增广)
#include <queue> #include <stack> #include <cstdio> #include <cstring> #include <algorithm> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=l;i>=r;--i) using namespace std; typedef long long s64; const int M=4e3+5; const int N=6e4+5; const int inf=0x7fffffff; int n,m,S,T; int dep[M],e_size,head[M]; int be[M],low[M],dfn[M],time_; stack <int> sta; struct edge{ int u,v,w,nxt; }e[N*10]; void e_add(int u,int v,int w) { e[++e_size]=(edge){u,v,w,head[u]}; head[u]=e_size; } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } int Dfs(int x,int cp) { if(x==T) return cp; int las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w&&las) { q=Dfs(v,min(e[i].w,las)); if(!q) {dep[v]=0;continue;} las-=q,e[i].w-=q,e[i^1].w+=q; } } return cp-las; } void tarjan(int x) { low[x]=dfn[x]=++time_; sta.push(x); for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(!e[i].w) continue; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(!be[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { ++be[0]; while(1) { int tmp=sta.top(); sta.pop(); be[tmp]=be[0]; if(x==tmp) break; } } } int main() { //freopen("a.txt","r",stdin); scanf("%d%d%d%d",&n,&m,&S,&T); e_size=1; rep(i,1,m) { int u,v,w; scanf("%d%d%d",&u,&v,&w); e_add(u,v,w),e_add(v,u,0); } while (Bfs()) Dfs(S,inf); rep(i,1,n) if(!dfn[i]) tarjan(i);//脑残吗 for(int i=2;i<=e_size;i+=2) { if(e[i].w) puts("0 0"); else { be[e[i].u]==be[e[i].v]?printf("0 "):printf("1 "); be[e[i].u]==be[S]&&be[e[i].v]==be[T]?puts("1"):puts("0"); } } }
bzoj 3281
边转化为点用支配树求出必经边
因为必经点所以$dis[nxt]-dis[pre]$就是最短路径
得到数列单调指针覆盖即可
注意脑子不清醒写的代码一定要重写
#include <set> #include <stack> #include <ctime> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #define fir first #define sec second #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define per(i,l,r) for(int i=(l);i>=(r);--i) using namespace std; typedef long long s64; const int M=5e5+5; int n,m,S,T,len; int head[M],e_size,dis[M]; int st[M],id[M],sdom[M],idom[M]; int be[M],f[M],fa[M],sta[M],g[M]; bool vis[M]; vector <int> to[M],pre[M],buc[M]; struct edge{ int u,v,w,nxt; }e[M*5]; void e_add(int u,int v,int w) { e[++e_size]=(edge){u,v,w,head[u]}; head[u]=e_size; } void dijkstra() { rep(i,1,n) dis[i]=2147483647; dis[S]=0; set <pair<int,int> > q; q.insert(make_pair(0,S)); int cnt=0; while (!q.empty()) { ++cnt; pair<int,int> r=*q.begin(); q.erase(q.begin()); if(dis[r.sec]!=r.fir) continue; for(int i=head[r.sec];i;i=e[i].nxt) { int v=e[i].v; if(dis[v]>dis[r.sec]+e[i].w) { dis[v]=dis[r.sec]+e[i].w; q.insert(make_pair(dis[v],v)); } } } } void dfs(int x) { id[x]=++id[0]; st[id[0]]=x; be[x]=x; f[x]=x; sdom[x]=id[x];// for(int v,i=to[x].size()-1;i>=0;--i) { v=to[x][i]; if(!id[v]) fa[v]=x,dfs(v); } } int find(int x) { if(x==be[x]) return f[x]; int now=find(be[x]); be[x]=be[be[x]]; if(sdom[now]<sdom[f[x]]) f[x]=now; return f[x]; } void make_dominator_tree() { rep(i,1,m) { int u=e[i].u,v=e[i].v; to[u].push_back(n+i); to[n+i].push_back(v); pre[n+i].push_back(u); pre[v].push_back(n+i); } dfs(S); per(i,id[0],2) { int p=st[i]; for(int i=pre[p].size()-1;i>=0;--i) { int v=pre[p][i]; if(id[v]) sdom[p]=min(sdom[p],sdom[find(v)]); } be[p]=fa[p]; buc[st[sdom[p]]].push_back(p); for(int i=buc[fa[p]].size()-1;i>=0;--i) { int v=buc[fa[p]][i]; int u=find(v); if(sdom[u]==sdom[v]) vis[v]=1,idom[v]=sdom[v]; else idom[v]=u; } } rep(i,2,id[0]) if(!vis[st[i]]) idom[st[i]]=idom[idom[st[i]]];//vis[st[i]]啊 } void get_ans() { int cnt=0; int pre=-1,now=st[idom[T]]; while (now&&now<=n) now=st[idom[now]]; while (now) { if(pre!=-1) { sta[++cnt]=dis[e[pre-n].u]-dis[e[now-n].v]; } sta[++cnt]=e[now-n].w; pre=now; now=st[idom[now]]; while (now&&now<=n) now=st[idom[now]]; } int tot=0; rep(i,1,cnt+1>>1) tot+=sta[2*i-1]; int ans=tot; for(int l=cnt,r=cnt,num=0,sum[2]={0};l>=1;--l) { num+=sta[l]*(l&1); sum[0]+=sta[l],sum[1]+=sta[l]*(l&1); while (sum[0]>2*len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),--r; ans=min(ans,tot-sum[1]-(r+1<=cnt&&r+1&1)*(2*len-sum[0])); } for(int l=cnt,r=cnt,num=0,sum[2]={0};l>=1;--l) { num+=sta[l]*(l&1); sum[0]+=sta[l],sum[1]+=sta[l]*(l&1); while (sum[0]>len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),--r; g[l]=num-sum[1]-(r+1<=cnt&&r+1&1)*(len-sum[0]); } per(i,cnt-1,1) g[i]=min(g[i],g[i+1]+sta[i]*(i&1)); for(int l=1,r=1,num=0,sum[2]={0};l<=cnt;++l) { num+=sta[l]*(l&1); sum[0]+=sta[l],sum[1]+=sta[l]*(l&1); while (sum[0]>len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),++r; ans=min(ans,g[l+1]+num-sum[1]-(r-1>=1&&r-1&1)*(len-sum[0])); } printf("%d\n",ans); } int main() { //freopen("a.txt","r",stdin); int test_; scanf("%d",&test_); while (test_--) { scanf("%d%d%d%d%d",&n,&m,&S,&T,&len); ++S,++T; rep(i,1,m) { int x,y,z; scanf("%d%d%d",&x,&y,&z); ++x,++y; e_add(x,y,z); } dijkstra(); if(dis[T]>1000000000) puts("-1"); else{ make_dominator_tree(); get_ans(); } e_size=0; rep(i,0,n+m) f[i]=g[i]=be[i]=fa[i]=id[i]=st[i]=vis[i]=sta[i]=idom[i]=sdom[i]=head[i]=0; rep(i,1,n+m) to[i].clear(),pre[i].clear(),buc[i].clear(); } }
bzoj 3495
2-sat
加一个前缀和优化即可
#include <set> #include <stack> #include <ctime> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #define fir first #define sec second #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define per(i,l,r) for(int i=(l);i>=(r);--i) using namespace std; typedef long long s64; const int M=4e6+5; int n,m,K; int a[M],be[M]; int low[M],dfn[M],time_; stack <int> sta; int e_size,head[M]; struct edge{ int v,nxt; }e[M*5]; void e_add(int u,int v) { e[++e_size]=(edge){v,head[u]}; head[u]=e_size; } void tarjan(int x) { //cout<<"-_-"<<x<<endl; low[x]=dfn[x]=++time_; sta.push(x); for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; //cout<<x<<" "<<v<<endl; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(!be[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { ++be[0]; while (1) { int tmp=sta.top(); sta.pop(); be[tmp]=be[0]; if(x==tmp) break; } } } int main() { //freopen("a.txt","r",stdin); scanf("%d%d%d",&n,&m,&K); rep(i,1,m) { int x,y; scanf("%d%d",&x,&y); e_add(2*x-1,2*y); e_add(2*y-1,2*x); } int cnt=2*n; rep(i,1,K) { //cout<<"-_-"<<endl; int num; scanf("%d",&num); rep(j,1,num) scanf("%d",a+j); int pre=2*a[1]-1; rep(j,2,num) { e_add(2*a[j],pre); ++cnt; e_add(cnt,2*a[j]-1); e_add(cnt,pre); pre=cnt; } pre=2*a[num]-1; per(j,num-1,1) { e_add(2*a[j],pre); ++cnt; e_add(cnt,2*a[j]-1); e_add(cnt,pre); pre=cnt; } } rep(i,1,2*n) if(!dfn[i]) tarjan(i); rep(i,1,n) if(be[2*i]==be[2*i-1]) return puts("NIE"),0; puts("TAK"); }
bzoj 2730
点双连通分量
分析后发现给只包含一个割点的强连通分量放一个出口即可
特判没有割点的情况
#include <set> #include <stack> #include <ctime> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #define fir first #define sec second #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define per(i,l,r) for(int i=(l);i>=(r);--i) using namespace std; typedef long long s64; typedef unsigned long long u64; const int M=1e4+5; int n,m; int e_size,head[M]; int low[M],dfn[M],time_,be; bool is_cut[M]; vector <int> cc[M]; stack <int> sta; struct edge{ int v,nxt; }e[M*5]; void e_add(int u,int v) { e[++e_size]=(edge){v,head[u]}; head[u]=e_size; } void tarjan(int x,int las) { low[x]=dfn[x]=++time_; sta.push(x); int c=0; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(v==las) continue; if(!dfn[v]) { int pre=sta.top(); tarjan(v,x); low[x]=min(low[x],low[v]); if(low[v]>=dfn[x]) { ++c; is_cut[x]=1; ++be; while (1) { int tmp=sta.top(); if(tmp==pre) break; sta.pop(); cc[be].push_back(tmp); } cc[be].push_back(x); } } else low[x]=min(low[x],dfn[v]); } if(x==las&&c==1) is_cut[x]=0; } int main() { //freopen("a.txt","r",stdin); int test_=0; while (scanf("%d",&m)==1) { if(!m) break; n=0; rep(i,1,m) { int x,y; scanf("%d%d",&x,&y); n=max(n,max(x,y)); e_add(x,y),e_add(y,x); } rep(i,1,n) if(!dfn[i]) tarjan(i,i); if(be==1) { printf("Case %d: 2 %lld\n",++test_,1ll*n*(n-1)/2); } else { u64 ans[2]={0}; ans[1]=1; rep(i,1,be) { int t=0; for(int j=cc[i].size()-1;j>=0;--j) t+=is_cut[cc[i][j]]; if(t==1) ++ans[0],ans[1]*=cc[i].size()-1; } printf("Case %d: %llu %llu\n",++test_,ans[0],ans[1]); } time_=e_size=0; rep(i,1,n) low[i]=dfn[i]=head[i]=is_cut[i]=0; rep(i,1,be) cc[i].clear(); be=0; } }
bzoj 5219
竞赛图计数简单题
#include <set> #include <stack> #include <ctime> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #define fir first #define sec second #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define per(i,l,r) for(int i=(l);i>=(r);--i) using namespace std; typedef long long s64; typedef unsigned long long u64; const int M=2e3+5; int n,mod; int C[M][M]; int f[M],g[M],bin[M]; int qpow(int x,int k) { int t=1; for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) t=1ll*t*x%mod; return t; } void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;} int main() { //freopen("a.txt","r",stdin); scanf("%d%d",&n,&mod); rep(i,0,n) C[i][0]=1; rep(i,1,n) rep(j,1,i) inc(C[i][j]=C[i-1][j],C[i-1][j-1]); rep(i,0,n) bin[i]=qpow(2,i*(i-1)>>1); rep(i,1,n) { g[i]=bin[i]; rep(j,1,i-1) inc(g[i],mod-1ll*C[i][j]*g[j]%mod*bin[i-j]%mod); } //rep(i,1,n) cout<<g[i]<<" "; cout<<endl; rep(i,1,n) { int ans=0; rep(j,0,i-1) inc(ans,1ll*C[i-1][j]*g[j+1]%mod*bin[i-j-1]%mod); ans=1ll*ans*C[n-1][i-1]%mod*bin[n-i]%mod; printf("%d\n",ans); } puts(""); }
bzoj 3693
Hall定理
求$|S|-|T|$最小值显然枚举的$|S|$中的组的区间并是连续的
转化为枚举区间,求出区间包含的组的$a_{i}$的和即可
左端点单调用线段树维护右端点的区间加减求min即可
$O(n*logn)$
#include <set> #include <stack> #include <ctime> #include <queue> #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> #define fir first #define sec second #define rep(i,l,r) for(int i=(l);i<=(r);++i) #define per(i,l,r) for(int i=(l);i>=(r);--i) using namespace std; typedef long long s64; typedef unsigned long long u64; const int M=5e5+5; int n,m; int st[M],sta[M]; int Min[M*4],data[M*4]; struct node{ int x,id; bool operator <(const node &a) const { return x<a.x; } }p[M]; struct point { int l,r,x; bool operator <(const point &a) const { return l<a.l; } }a[M]; void push_down(int g) { data[g<<1]+=data[g]; data[g<<1|1]+=data[g]; Min[g<<1]+=data[g]; Min[g<<1|1]+=data[g]; data[g]=0; } void T_add(int g,int l,int r,int lx,int rx,int x) { if(lx<=l&&rx>=r) return Min[g]+=x,data[g]+=x,void(); if(data[g]) push_down(g); int mid=l+r>>1; if(lx<=mid) T_add(g<<1,l,mid,lx,rx,x); if(rx>mid) T_add(g<<1|1,mid+1,r,lx,rx,x); Min[g]=min(Min[g<<1],Min[g<<1|1]); } int query(int g,int l,int r,int lx,int rx) { if(lx<=l&&rx>=r) return Min[g]; if(data[g]) push_down(g); int ans=2e9; int mid=l+r>>1; if(lx<=mid) ans=min(ans,query(g<<1,l,mid,lx,rx)); if(rx>mid) ans=min(ans,query(g<<1|1,mid+1,r,lx,rx)); return ans; } signed main() { //freopen("a.txt","r",stdin); //freopen("a.out","w",stdout); int test_; scanf("%d",&test_); while (test_--) { scanf("%d%d",&n,&m); s64 sum=0; rep(i,1,n) { scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].x); if(a[i].l>a[i].r) a[i].r+=m; sum+=a[i].x; } if(sum>m) { puts("No"); continue; } int cnt=n; rep(i,1,n) if(a[i].r<m) a[++cnt]=(point){a[i].l+m,a[i].r+m,a[i].x}; n=cnt; rep(i,1,n) p[2*i-1]=(node){a[i].l,2*i-1},p[2*i]=(node){a[i].r,2*i}; sort(p+1,p+2*n+1); p[0].x=p[1].x-1; rep(i,1,2*n) { if(p[i].x!=p[i-1].x) ++st[0]; st[st[0]]=p[i].x; sta[p[i].id]=st[0]; } rep(i,1,n) a[i].l=sta[2*i-1],a[i].r=sta[2*i]; sort(a+1,a+n+1); rep(i,1,st[0]) T_add(1,1,st[0],i,i,st[i]-st[1]+1); rep(i,1,n) T_add(1,1,st[0],a[i].r,st[0],-a[i].x); //rep(i,1,st[0]) cout<<query(1,1,st[0],i,i)<<" "; cout<<endl;while (1); int ans=0; int head_=1,tail_=1; rep(i,1,st[0]) { while (tail_+1<=st[0]&&st[tail_+1]-st[i]<m) ++tail_; ans=query(1,1,st[0],i,tail_); if(ans<0) break; while (a[head_].l==i) T_add(1,1,st[0],a[head_].r,st[0],a[head_].x),++head_; T_add(1,1,st[0],i,st[0],st[i]-st[i+1]); } ans<0?puts("No"):puts("Yes"); st[0]=0; rep(i,0,16*n) Min[i]=data[i]=0; } }
bzoj 3894
最小割
将st看作文理
新建(s,x',same_art)并用same_art限制5个点即可
same_sci同理对称新建点即可
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #define rep(i,l,r) for(int i=l;i<=r;++i) #define per(i,l,r) for(int i=r;i>=l;--i) using namespace std; typedef long long s64; const int N=105; const int M=4e4+5; const int inf=2e9; int n,m; int art[N][N],sci[N][N]; int same_art[N][N],same_sci[N][N]; int S,T,dep[M],e_size,head[M]; int x_[4]={0,0,1,-1},y_[4]={1,-1,0,0}; struct edge { int v,w,nxt; }e[M*10]; void e_add(int u,int v,int w) { e[++e_size]=(edge){v,w,head[u]}; head[u]=e_size; } void insert(int u,int v,int w) { e_add(u,v,w),e_add(v,u,0); } bool Bfs() { queue <int> q; memset(dep,0,sizeof(dep)); dep[S]=1; q.push(S); while (!q.empty()) { int r=q.front(); q.pop(); for(int i=head[r];i;i=e[i].nxt) { int v=e[i].v; if(!dep[v]&&e[i].w) { dep[v]=dep[r]+1; q.push(v); if(v==T) return 1; } } } return 0; } int Dfs(int x,int cp) { if(x==T) return cp; int las=cp,q; for(int i=head[x];i;i=e[i].nxt) { int v=e[i].v; if(dep[v]==dep[x]+1&&e[i].w&&las) { q=Dfs(v,min(las,e[i].w)); if(!q) {dep[v]=0;continue;} e[i].w-=q,las-=q,e[i^1].w+=q; if(!las) break; } } return cp-las; } int main() { //freopen("a.txt","r",stdin); S=M-2,T=M-1; e_size=1; scanf("%d%d",&n,&m); rep(i,1,n) rep(j,1,m) scanf("%d",art[i]+j); rep(i,1,n) rep(j,1,m) scanf("%d",sci[i]+j); rep(i,1,n) rep(j,1,m) scanf("%d",same_art[i]+j); rep(i,1,n) rep(j,1,m) scanf("%d",same_sci[i]+j); int ans=0; rep(i,1,n) rep(j,1,m) { ans+=art[i][j]+sci[i][j]; ans+=same_art[i][j]+same_sci[i][j]; int x=(i-1)*m+j; insert(S,x,art[i][j]); insert(x,T,sci[i][j]); insert(x,x+n*m,inf); insert(x+n*m,T,same_sci[i][j]); insert(S,x+2*n*m,same_art[i][j]); insert(x+2*n*m,x,inf); rep(k,0,3) { int ii=i+x_[k],jj=j+y_[k]; if(ii<1||ii>n||jj<1||jj>m) continue; int xx=(ii-1)*m+jj; insert(x+2*n*m,xx,inf); insert(xx,x+n*m,inf); } } while (Bfs()) ans-=Dfs(S,inf); cout<<ans<<endl; }
bzoj 3436
差分约束裸题