2019.3.18
C O D E
T1
树上直接贪心,环上for一遍贪心
哇说的简单,码了将近一下午终于码出来了
想好了就果断写啊
废话结束
对于入度大于一且不在环上的点直接贪心留最大的
对于一个完美无瑕的环直接断最小的(指没有被环以外的点指着)
对于入度大于一且在环上的点,先假装它就是普通的入度大于一的点来做并记录每个点是否断了环上的边和断的边中的最大值;最后把没有删边的不完美的环每个单独拿出来,枚举到底断那一条边修正答案
细节不说了,这种题的细节也没啥可说的。。。
(为了避免伤害眼睛已经删掉了调试语句
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 #include<algorithm> 5 #define vint vector<int> 6 #define vit vector<int>::iterator 7 using namespace std; 8 const int N=100005; 9 int p[N],noww[N],goal[N]; 10 int rec[N],cst[N],inc[N],col[N]; 11 int deg[N],aset[N],stk[N],vis[N]; 12 int cal[N],cut[N],brk[N],spe[N],mae[N]; 13 int n,dfn,cnt,tot,top; long long ans; vint ve[N],cr[N]; 14 void Link(int f,int t) 15 { 16 noww[++cnt]=p[f]; 17 goal[cnt]=t,p[f]=cnt; 18 } 19 int Finda(int x) 20 { 21 return x==aset[x]?x:aset[x]=Finda(aset[x]); 22 } 23 bool Bigcir() 24 { 25 int tmp=0; 26 for(int i=1;i<=n;i++) 27 { 28 if(Finda(i)==i) tmp++; 29 if(deg[i]!=1) return false; 30 } 31 return tmp==1; 32 } 33 void DFS(int nde) 34 { 35 stk[++top]=nde,vis[nde]=dfn; 36 for(int i=p[nde],g;i;i=noww[i]) 37 if(!vis[g=goal[i]]) DFS(g); 38 else if(vis[g]==dfn) 39 { 40 int ori=g,pts=top; tot++; 41 while(stk[pts]!=ori) 42 { 43 int tmp=stk[pts--]; 44 cr[tot].push_back(tmp); 45 col[tmp]=tot,inc[tmp]=true; 46 } 47 cr[tot].push_back(ori); 48 col[ori]=tot,inc[ori]=true; 49 } 50 top--; 51 } 52 int main() 53 { 54 scanf("%d",&n); 55 for(int i=1;i<=n;i++) aset[i]=i; 56 for(int i=1;i<=n;i++) 57 { 58 scanf("%d%d",&rec[i],&cst[i]); 59 Link(i,rec[i]),ve[rec[i]].push_back(i); 60 aset[Finda(i)]=Finda(rec[i]),deg[rec[i]]++; 61 } 62 if(Bigcir()) printf("0"),exit(0); 63 else 64 { 65 cst[n+1]=1e9; 66 for(int i=1;i<=n;i++) 67 if(!vis[i]) dfn++,DFS(i); 68 for(int i=1;i<=n;i++) 69 if(deg[i]>1&&inc[i]) 70 { 71 int t,o=0,c=col[i],kao; 72 for(vit it=ve[i].begin();it!=ve[i].end();it++) 73 { 74 if(!cut[t=*it]&&cst[t]>cst[o]) o=t; 75 if(inc[t]) kao=t; 76 } 77 for(vit it=ve[i].begin();it!=ve[i].end();it++) 78 if(!cut[t=*it]&&t!=o) 79 { 80 cut[t]=true,mae[i]=max(mae[i],cst[t]); 81 if(t==kao) brk[c]=true; 82 } 83 cal[c]=true,spe[i]=true; 84 } 85 for(int i=1;i<=n;i++) 86 if(deg[i]>1&&!inc[i]) 87 { 88 int t,o=0; 89 for(vit it=ve[i].begin();it!=ve[i].end();it++) 90 if(!cut[t=*it]&&cst[t]>cst[o]) o=t; 91 for(vit it=ve[i].begin();it!=ve[i].end();it++) 92 if((t=*it)!=o) cut[t]=true,deg[rec[t]]--; 93 } 94 for(int i=1;i<=tot;i++) 95 if(!cal[i]) 96 { 97 int t,o=n+1; 98 for(vit it=cr[i].begin();it!=cr[i].end();it++) 99 if(!cut[(t=*it)]&&cst[t]<cst[o]) o=t; 100 cut[o]=true,deg[rec[o]]--; 101 } 102 } 103 for(int i=1;i<=n;i++) 104 if(cut[i]) ans+=cst[i]; 105 for(int i=1;i<=tot;i++) 106 if(cal[i]&&!brk[i]) 107 { 108 int t; long long tep=1e18; 109 for(vit it=cr[i].begin();it!=cr[i].end();it++) 110 if(!spe[rec[t=*it]]) tep=min(tep,ans+cst[t]); 111 else tep=min(tep,ans+cst[t]-mae[rec[t]]); 112 ans=tep; 113 } 114 printf("%lld",ans); 115 return 0; 116 }
T2
逐行地每次正反都做一遍DP,记录从哪里吃过来,对应地递归吃后面的
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=405,inf=0x3f3f3f3f; 6 int n,m,vis[N][N],dp[N][N]; 7 char str[N][N]; 8 void Mini(int &x,int y) 9 { 10 if(x>y) x=y; 11 } 12 bool Out(int a,int b) 13 { 14 return a<1||b<1||a>n||b>m; 15 } 16 int DFS(int x,int y,int t) 17 { 18 if(Out(x,y)) return 0; 19 int &vs=vis[x][y]; 20 if(~vs) return vs?0:inf; 21 vs=0; int ret=2; 22 if(str[x][y]=='Z') 23 { 24 if(t<2) ret+=DFS(x+1,y,0)+DFS(x,y+1,1); 25 else ret+=DFS(x-1,y,2)+DFS(x,y-1,3); 26 Mini(ret,inf); 27 } 28 else 29 { 30 if(t==1||t==2) ret+=DFS(x,y+1,1)+DFS(x-1,y,2); 31 else ret+=DFS(x+1,y,0)+DFS(x,y-1,3); 32 Mini(ret,inf); 33 } 34 if(ret!=inf) vs=1; 35 return ret; 36 } 37 int main() 38 { 39 scanf("%d%d",&n,&m); 40 for(int i=1;i<=n;i++) 41 scanf("%s",str[i]+1); 42 memset(dp,0x3f,sizeof dp); 43 for(int i=1;i<=n;i++) 44 { 45 memset(vis,-1,sizeof vis); 46 for(int j=1,t=0;j<=m;j++) 47 t+=DFS(i,j,3),Mini(t,inf),Mini(dp[i][j],t); 48 memset(vis,-1,sizeof vis); 49 for(int j=m,t=0;j;j--) 50 t+=DFS(i,j,1),Mini(t,inf),Mini(dp[i][j],t); 51 } 52 for(int i=1;i<=n;i++) 53 for(int j=1;j<=m;j++) 54 { 55 if(dp[i][j]==inf) printf("-1"); 56 else printf("%d",dp[i][j]); 57 j==m?puts(""):putchar(' '); 58 } 59 return 0; 60 }
T3
观察到顺序不影响答案,分块打标记
注意分开处理两边零散块是有顺序的
(已经忘掉有分块这个东西了TAT
1 #pragma GCC optimize(3) 2 #include<queue> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #define vint vector<int> 7 #define gint greater<int> 8 #define prq priority_queue 9 using namespace std; 10 const int N=400005,Sq=660; 11 int n,m,rd,lp,rp,tg,sqr,tot; 12 int sus[N],bel[N],lpt[Sq],rpt[Sq]; 13 prq<int> mxx[Sq]; prq<int,vint,gint> tag[Sq]; 14 void Pre() 15 { 16 sqr=sqrt(n)+5,lpt[tot=1]=1; 17 for(int i=1;i<=n;i++) 18 { 19 bel[i]=(i-1)/sqr+1; 20 if(i%sqr==0) rpt[tot++]=i,lpt[tot]=i+1; 21 } 22 n%sqr?rpt[tot]=n:tot--; 23 } 24 void Create(int b) 25 { 26 mxx[b]=prq<int> (); 27 for(int i=lpt[b];i<=rpt[b];i++) mxx[b].push(sus[i]); 28 } 29 void Release(int b) 30 { 31 if(!tag[b].empty()) 32 { 33 for(int i=lpt[b];i<=rpt[b];i++) 34 if(tag[b].top()<sus[i]) 35 tag[b].push(sus[i]),sus[i]=tag[b].top(),tag[b].pop(); 36 } 37 tag[b]=prq<int,vint,gint> (); 38 } 39 int Round(int l,int r,int s) 40 { 41 if(bel[l]==bel[r]) 42 { 43 int b=bel[l]; 44 Release(b); 45 for(int i=l;i<=r;i++) 46 if(s<sus[i]) swap(s,sus[i]); 47 Create(b); 48 } 49 else 50 { 51 int b1=bel[l],b2=bel[r]; 52 Release(b1); 53 for(int i=l;i<=rpt[b1];i++) 54 if(s<sus[i]) swap(s,sus[i]); Create(b1); 55 for(int i=b1+1;i<=b2-1;i++) 56 if(s<mxx[i].top()) 57 { 58 int tmp=mxx[i].top(); mxx[i].pop(); 59 mxx[i].push(s),tag[i].push(s),s=tmp; 60 } 61 Release(b2); 62 for(int i=lpt[b2];i<=r;i++) 63 if(s<sus[i]) swap(s,sus[i]); Create(b2); 64 } 65 return s; 66 } 67 int main() 68 { 69 scanf("%d%d",&n,&m),Pre(); 70 for(int i=1;i<=n;i++) scanf("%d",&sus[i]); 71 for(int i=1;i<=tot;i++) Create(i); 72 for(int i=1;i<=m;i++) 73 { 74 scanf("%d%d%d",&lp,&rp,&tg); 75 if(lp>rp) tg=Round(lp,n,tg),lp=1; 76 printf("%d ",Round(lp,rp,tg)); 77 } 78 return 0; 79 }
2019.3.19
肥肠爆芡,因为沙茶博主昨天在沙茶学校的沙茶食堂吃坏了肚子,所以这场考试咕咕了
开始补档
T1
一开始找x坐标或y坐标最大的点,然后看下一次转向,左转就走极角最大的,右转就走极角最小的
其实扫一遍就可以,然而我傻乎乎地每次都排了个序
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=5005; 6 struct a{int xp,yp,idx;}o,pt[N],cp[N]; 7 bool cmp(a x,a y) 8 { 9 return x.xp==y.xp?x.yp<y.yp:x.xp<y.xp; 10 } 11 long long Cha(a x,a y) 12 { 13 return 1ll*(x.xp-o.xp)*(y.yp-o.yp)-1ll*(y.xp-o.xp)*(x.yp-o.yp); 14 } 15 bool cop(a x,a y) 16 { 17 return Cha(x,y)<0; 18 } 19 int n,m,vis[N],ans[N]; char str[N]; 20 void Solve(int p,int l,int r,a q) 21 { 22 vis[q.idx]=true,ans[p]=q.idx; 23 if(p==n) return; 24 o=q,sort(cp+l,cp+1+r,cop); 25 if(str[p]=='L') Solve(p+1,l,r-1,cp[r]); 26 else Solve(p+1,l+1,r,cp[l]); 27 } 28 int main() 29 { 30 scanf("%d",&n); 31 for(int i=1;i<=n;i++) 32 scanf("%d%d",&pt[i].xp,&pt[i].yp),pt[i].idx=i; 33 scanf("%s",str+1); 34 sort(pt+1,pt+1+n,cmp); 35 for(int i=1;i<=n;i++) cp[i]=pt[i]; 36 Solve(1,1,n-1,pt[n]); 37 for(int i=1;i<=n;i++) printf("%d ",ans[i]); 38 return 0; 39 }
T2
推性质题,我们发现每个人感染的是一段区间的人,然后就转成了线段覆盖的方案数,树状数组优化
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define vint vector<int> 5 #define vit vector<int>::iterator 6 using namespace std; 7 const int N=200005,mod=1e9+7; 8 int n,ans,uni[N],spd[N],bit[N],pre[N],suf[N]; 9 struct a{int pos,spe;}pt[N]; vint ve[N]; 10 bool cmp(a x,a y){return x.pos<y.pos;} 11 void Add(int &x,int y){x+=y; if(x>=mod) x-=mod;} 12 void Modify(int x,int y) 13 { 14 while(x<=n) 15 Add(bit[x],y),x+=x&-x; 16 return; 17 } 18 int Query(int x) 19 { 20 int ret=0; 21 while(x>0) 22 Add(ret,bit[x]),x-=x&-x; 23 return ret; 24 } 25 int main() 26 { 27 register int i; 28 scanf("%d",&n); 29 for(i=1;i<=n;i++) 30 scanf("%d%d",&pt[i].pos,&pt[i].spe),uni[i]=pt[i].spe; 31 sort(pt+1,pt+1+n,cmp),sort(uni+1,uni+1+n); 32 int lth=unique(uni+1,uni+1+n)-uni-1; 33 for(i=1;i<=n;i++) spd[i]=lower_bound(uni+1,uni+1+lth,pt[i].spe)-uni; 34 for(i=1;i<=n;i++) pre[i]=max(pre[i-1],spd[i]); 35 for(i=n,suf[n+1]=1e9;i;i--) suf[i]=min(suf[i+1],spd[i]); 36 for(int i=1;i<=n;i++) ve[pre[i]].push_back(suf[i]); 37 for(int i=1,t,tmp;i<=n;i++) 38 for(vit it=ve[i].begin();it!=ve[i].end();it++) 39 { 40 t=*it,tmp=(Query(i)-Query(t-2)+(t<2)+mod)%mod; 41 Modify(i,tmp); if(i==n) Add(ans,tmp); 42 } 43 printf("%d",ans); 44 return 0; 45 }
T3
这题......
(orz ztb tql)
2019.3.21
T1
容斥/点分治
咕咕咕
T2
转化成完全二分图的哈密顿回路
然后考场推到这里不会去重,搞出来一个整数划分,没了
去重的方法是我们选定第一个回路经过左边第一个,然后就有
T3
orz yzh tql
模拟费用流,在每一只鸟进来之后找离这只鸟最近的还有空的点,正确性参考费用流
具体来说要支持树上边权取反和查询到所有合法点的最短路,因为树高只有log,暴力爬树维护
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=300005,inf=1e9; 6 int nes[N],gu[N],flw[N],dp[N],bes[N],n,m,ans; 7 void Maintain(int nde) 8 { 9 int ls=2*nde,rs=2*nde+1; dp[nde]=inf; 10 if(ls<=n&&dp[ls]+(flw[ls]>=0?1:-1)<dp[nde]) 11 dp[nde]=dp[ls]+(flw[ls]>=0?1:-1),bes[nde]=bes[ls]; 12 if(rs<=n&&dp[rs]+(flw[rs]>=0?1:-1)<dp[nde]) 13 dp[nde]=dp[rs]+(flw[rs]>=0?1:-1),bes[nde]=bes[rs]; 14 if(nes[nde]&&dp[nde]>=0) dp[nde]=0,bes[nde]=nde; 15 } 16 void Pushup(int nde) 17 { 18 Maintain(nde); 19 if(nde!=1) Pushup(nde>>1); 20 } 21 void Gu(int nde) 22 { 23 int x=nde,tmp=0,bsf=inf,bsp=0,bsn=0; 24 while(x) 25 { 26 int tep=tmp+dp[x]; 27 if(tep<bsf) bsf=tep,bsp=bes[x],bsn=x; 28 tmp+=(flw[x]<=0?1:-1),x>>=1; 29 } 30 ans+=bsf,nes[bsp]--; 31 int mem1=nde,mem2=bsp; 32 while(nde!=bsn) flw[nde]--,nde>>=1; 33 while(bsp!=bsn) flw[bsp]++,bsp>>=1; 34 Pushup(mem1),Pushup(mem2); 35 } 36 int main() 37 { 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=n;i++) scanf("%d",&nes[i]); 40 for(int i=1;i<=m;i++) scanf("%d",&gu[i]); 41 for(int i=n;i;i--) Maintain(i); 42 for(int i=1;i<=m;i++) Gu(gu[i]),printf("%d ",ans); 43 return 0; 44 }