2019 7 8 HL 模拟赛
今天 很不爽 昨天晚上没有睡好觉 大约2点才睡着吧 反正翻来覆去睡不着 不知道为什么可能可行流 或者可行费用流并没有深刻理解 。我不会写 让我心情非常的焦躁。
大凶 顺理成章的被3位强者吊着锤(妈呀我想吊锤他们啊。。
第一题 哇 这不是求两点之间的最短路径么 ? 圆方树直接上啊 。。好像正解不需要但是多了也不多。
然后成功挂掉了 可能心情很烦躁 然后没有多想直接样例过了 丢了没管
犯得 错误是 没有输出0 直接输出换行了 然后 应该输出0再输出换行的 真菜题都没读清。
还有一点是 输出0了没输出换行 真菜这都不知道哎 结果挂掉一堆分数 要不 应该 能得到一个自己满意的成绩 第一题挂彩了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define EPS 1e-8 using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const int MAXN=200010<<1,maxn=MAXN<<2; //m<=2n 且双向边 加上方边 空间8倍 int T; int n,m,num,cnt,top,len,len1,t,h,flag; int s[maxn],q[maxn],vis[maxn],pre[maxn]; int lin[maxn],ver[maxn],nex[maxn]; int dfn[maxn],low[maxn]; int lin1[maxn],ver1[maxn],nex1[maxn]; inline void add(int x,int y) { ver[++len]=y; nex[len]=lin[x]; lin[x]=len; } inline void add1(int x,int y) { ver1[++len1]=y; nex1[len1]=lin1[x]; lin1[x]=len1; } inline void tarjan(int x) { dfn[x]=low[x]=++num; s[++top]=x; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(!dfn[tn]) { tarjan(tn); low[x]=min(low[x],low[tn]); if(low[tn]==dfn[x]) { ++cnt; for(int y=0;y!=tn;--top) { y=s[top]; add1(cnt,y); add1(y,cnt); } add1(x,cnt); add1(cnt,x); } } else low[x]=min(low[x],dfn[tn]); } } inline void bfs() { t=h=0; memset(vis,0,sizeof(vis)); q[++t]=n;s[t]=0; while(h++<t) { int x=q[h];vis[x]=1; if(x==1)return; for(int i=lin1[x];i;i=nex1[i]) { int tn=ver1[i]; if(vis[tn])continue; pre[tn]=x;q[++t]=tn; s[t]=s[h]+(tn<=n?1:0); } } } int main() { //freopen("1.in","r",stdin); freopen("home.in","r",stdin); freopen("home.out","w",stdout); T=read(); while(T--) { len=len1=top=num=cnt=flag=0; memset(lin1,0,sizeof(lin1)); memset(lin,0,sizeof(lin)); memset(dfn,0,sizeof(dfn)); n=read();m=read();cnt=n; for(int i=1;i<=m;++i) { int x,y; x=read();y=read(); if(x==y)continue; add(x,y);add(y,x); if(x==1&&y==n)flag=1; if(y==1&&x==n)flag=1; } tarjan(1); if(!dfn[n]||flag){printf("%d\n",0);puts("");continue;} bfs();--s[h]; //cout<<h<<' '<<s[h]<<endl; printf("%d\n",s[h]); if(!s[h]){puts("");continue;} memset(vis,0,sizeof(vis)); int x=pre[1]; while(x!=n) { vis[x]=1; x=pre[x]; } int last=0; for(int i=2;i<n;++i) if(vis[i]) { if(last)printf("%d ",last); last=i; } printf("%d\n",last); } return 0; }
第二题植物大战僵尸可还行 题目比较 复杂把模型拿出来就比较简单了 注意判环即可。没挂还好。这个不对劲的人终于获得了欣慰。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline int read() { int x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } //空间只有64MB const int MAXN=33,maxn=MAXN*MAXN*MAXN*MAXN; int n,m,cnt,len,t,h,S,T,len1=1,sum,maxflow; int pos[MAXN][MAXN]; int a[MAXN*MAXN],vis[MAXN*MAXN]; int ru[MAXN*MAXN],q[MAXN*MAXN]; int lt[MAXN*MAXN],vt[maxn],nt[maxn]; int lin[MAXN*MAXN],ver[maxn<<1],nex[maxn<<1],e[maxn<<1]; inline void add(int x,int y) { vt[++len]=y;nt[len]=lt[x];lt[x]=len; } inline void add(int x,int y,int z) { ver[++len1]=y;nex[len1]=lin[x];lin[x]=len1;e[len1]=z; ver[++len1]=x;nex[len1]=lin[y];lin[y]=len1;e[len1]=0; } inline void topsort() { t=h=0; for(int i=1;i<=cnt;++i)if(ru[i]==0)q[++t]=i; while(h++<t) { int x=q[h]; for(int i=lt[x];i;i=nt[i]) { int tn=vt[i]; --ru[tn]; add(tn,x,INF); if(!ru[tn])q[++t]=tn; } } for(int i=1;i<=cnt;++i) { if(ru[i])continue; if(a[i]<0)add(i,T,-a[i]); else add(S,i,a[i]),sum+=a[i]; } } inline int bfs() { memset(vis,0,sizeof(vis)); t=h=0;q[++t]=S;vis[S]=1; while(h++<t) { int x=q[h]; for(int i=lin[x];i;i=nex[i]) { int tn=ver[i]; if(!e[i]||vis[tn])continue; vis[tn]=vis[x]+1; q[++t]=tn; if(tn==T)return 1; } } return 0; } inline int dinic(int x,int flow) { if(x==T)return flow; int rest=flow,k; for(int i=lin[x];i&&rest;i=nex[i]) { int tn=ver[i]; if(vis[tn]==vis[x]+1&&e[i]) { k=dinic(tn,min(e[i],rest)); if(!k){vis[tn]=0;continue;} e[i]-=k;e[i^1]+=k;rest-=k; } } return flow-rest; } int main() { //freopen("1.in","r",stdin); freopen("B.in","r",stdin); freopen("B.out","w",stdout); n=read();m=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j)pos[i][j]=++cnt; for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { a[pos[i][j]]=read(); if(j>1) { add(pos[i][j],pos[i][j-1]); ++ru[pos[i][j-1]]; } int w=read(); for(int k=1;k<=w;++k) { int x,y; x=read()+1;y=read()+1; ++ru[pos[x][y]]; add(pos[i][j],pos[x][y]); } } } S=cnt+1;T=S+1; topsort(); int flow=0; while(bfs())while((flow=dinic(S,INF)))maxflow+=flow; printf("%d\n",max(0,sum-maxflow)); return 0; }
第三题 区间操作 感觉是一流对多流? 好像不太行 仔细发现还是可以差分的变成单点操作 。
发现是一张二分图 我是差分后想到了二分一个值 区间最小值 然后维护整个区间都>=二分这个值即可。
然后乱建边 最后发现好像是个单峰函数 事实上这已经是我的败笔了因为单峰函数一出现三分随之而来 且非常不好写 应该停下 但是我仍然刚了1h 然后最后无奈拿到30分的辛苦分。我服了。
因为根本不需要知道那个最小值是多少 因为第一个值好像没什么卵用。只要后面的数比这个数大就好了二分或者三分这个值意义并不大。
下面说中午我稍微思考了一下想到的正解 真的比较简单 。对于一个差分过后数列来说我想到的是每一个位置上的数字如果小于0的话一定是不和法的我们期望的是将这个序列上的所有数字都>=0这样就好了,
观察+操作 发现l+1 (r+1)-1 这样 r如果是正数 其实就是负数向正数要1 显然正数和负数形成了二分图 具体做法就是这样。显然对于一个负数是拥有下界 全部连向源点下界成功被转换了。
再跑费用流即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//#include<bits/stdc++.h> #include<iomanip> #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<queue> #include<deque> #include<cmath> #include<ctime> #include<cstdlib> #include<stack> #include<algorithm> #include<vector> #include<cctype> #include<utility> #include<set> #include<bitset> #include<map> #define INF 1000000000 #define ll long long #define min(x,y) ((x)>(y)?(y):(x)) #define max(x,y) ((x)>(y)?(x):(y)) #define RI register ll #define db double #define EPS 1e-8 using namespace std; char buf[1<<15],*fs,*ft; inline char getc() { return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; } inline ll read() { ll x=0,f=1;char ch=getc(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();} return x*f; } const ll MAXN=210,maxn=MAXN*MAXN<<2; ll n,m,minn=INF,maxx,S,T,T1,len=1,h,t1,p; ll a[MAXN],b[MAXN]; ll pre[MAXN],in[MAXN],vis[MAXN],q[maxn<<1],dis[maxn]; ll lin[MAXN],ver[maxn<<1],nex[maxn<<1],e[maxn<<1],e1[maxn<<1]; struct wy { ll op,l,c; }t[MAXN]; inline void add(ll x,ll y,ll z,ll z1) { ver[++len]=y;nex[len]=lin[x];lin[x]=len;e[len]=z;e1[len]=z1; ver[++len]=x;nex[len]=lin[y];lin[y]=len;e[len]=0;e1[len]=-z1; } inline ll spfa() { for(ll i=1;i<=T;++i)dis[i]=INF; h=t1=0; dis[S]=0;vis[S]=1;in[S]=INF;q[++t1]=S; while(h++<t1) { ll x=q[h];vis[x]=0; for(ll i=lin[x];i;i=nex[i]) { ll tn=ver[i]; if(!e[i])continue; if(dis[tn]>dis[x]+e1[i]) { dis[tn]=dis[x]+e1[i]; in[tn]=min(in[x],e[i]); pre[tn]=i; if(!vis[tn])q[++t1]=tn,vis[tn]=1; } } } return dis[T]!=INF; } inline ll EK() { ll maxflow=0,sum=0; while(spfa()) { ll x=T,i=pre[x]; sum+=dis[x]*in[T]; maxflow+=in[T]; while(x!=S) { e[i]-=in[T]; e[i^1]+=in[T]; x=ver[i^1];i=pre[x]; } } if(maxflow!=p)return -1; return sum; } int main() { //freopen("1.in","r",stdin); freopen("seq.in","r",stdin); freopen("seq.out","w",stdout); n=read();m=read();T1=n+1;S=T1+1;T=S+1; for(ll i=1;i<=n;++i)a[i]=read(); for(ll i=1;i<=m;++i) { char op;ll x,y; op=getc(); while(op==' '||op=='\n')op=getc(); x=read();y=read(); t[i]=(wy){op=='-'?0:1,x,y}; } if(n==1){printf("%d\n",0);return 0;} for(ll i=2;i<=n;++i)b[i]=a[i]-a[i-1]; b[T1]=INF; for(ll i=2;i<=n+1;++i) { if(b[i]>0)add(i,T,b[i],0); else add(S,i,-b[i],0),p+=-b[i]; } add(1,T,INF,0); for(ll i=1;i<=n;++i) for(ll j=1;j<=m;++j) { if(t[j].op) { ll l=i,r=i+t[j].l; if(r>T1)continue; add(l,r,INF,t[j].c); } else { ll l=i,r=l+t[j].l; if(r>T1)continue; add(r,l,INF,t[j].c); } } printf("%lld\n",EK()); return 0; }
GG 总有一天我将会AK的 (突然WN附体嘻嘻。