[考试反思]0401省选模拟59:更改
这次考试$OJ$与$pdf$上编译选项不一样。考试结束时按照$pdf$上的来了。
结果后来又说要重测然后就出现了大批大批的$CE$。
我看到这第一反应是苟,于是非常憋屈的不使用$c++11$特性的同时也不去碰关键字。好歹是没$CE$(这要是$CE$了名次就滚到哪里去了
然而这场考试我考得非常弱智。。。
全场的前两个提交就是$gls$和我交的$T2$。交的很早然后也很自信,后来也都没再交,结果拿了个$10pts$
猜错结论了。想的太简单了。(还过了仨样例。。。
$T1$毒瘤出题人卡常,那也就没啥好说的。。
$T3$的话,思路倒是有,想的也差不多了,但是没具体想做法,觉得很麻烦,就写暴力了
然后弱智出题人$O(Tn^2)$的暴力出成$n=5000,T=10$。结果全场都没人拿到这档分。(然而还是感觉好亏
其实题都不算太难,想想也都能想出来。主要是$T2$这种事情。。。以后还是得回来看的。。。
T1:杨柳
大意:棋盘,$n$个起始点与终止点,有若干位置坏了,每个起始点都有一个棋子,每次可以跳马步$(a,b)$。$8$种走法。
要求任意时刻棋子不能出现在同一个格子里,求最少多少步让所有棋子都在终止点上(无对应关系)。$n\le 500,r,c \le 100$
首先有一个结论:不必考虑棋子在同一个格子里的问题,你可以通过强制先后顺序或者交换路径来避免这种事情发生。
如果一个格子里有棋子,导致其他某个格子不能动了,那最终结果一定是无解。
所以只需要二分图最大全匹配就可以。然而出题人卡掉了$zkw$费用流。
但是我们发现这样建图边数是$n^2+2n$的,点数是$2n+2$的。
如果我们直接在原图上建图那么点数是$(rc)^2+2$的,边数是$O(8(rc)^2)$的。
后者的边数更小,实测跑的快,所以采用后一种建图跑$zkw$费用流就行了。
谁会没事去学$KM$啊出题人是够无聊的了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define M 3888888 4 int dx[9],dy[9],a,b,n,r,c,fir[M],l[M],to[M],v[M],w[M],ec=1; 5 int T,MF,ans,D[M],al[M],q[M],iq[M],o[111][111]; char s[111][111]; 6 void link(int a,int b,int V,int W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;} 7 void con(int a,int b,int W,int V=1){link(a,b,V,W);link(b,a,0,-W);} 8 bool BFS(){ 9 for(int i=1;i<=T;++i)D[i]=166666666,al[i]=0; 10 for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(v[i]&&D[to[i]]>D[q[h]]+w[i]){ 11 if(!iq[to[i]])q[++t]=to[i]; 12 D[to[i]]=D[q[h]]+w[i],iq[to[i]]=1; 13 }return D[T]<166666666; 14 } 15 int dfs(int p,int f){int r=f; 16 if(p==T)return f; al[p]=1; 17 for(int i=fir[p];i&&r;i=l[i])if(!al[to[i]]&&D[to[i]]==D[p]+w[i]&&v[i]) 18 if(dfs(to[i],1))r--,v[i]--,v[i^1]++,ans+=w[i]; 19 else D[to[i]]=-1; 20 return f-r; 21 } 22 int main(){ 23 cin>>r>>c>>n>>a>>b; 24 dx[0]=dx[1]=dy[4]=dy[5]=a; 25 dy[1]=dy[2]=dx[5]=dx[6]=b; 26 dx[2]=dx[3]=dy[6]=dy[7]=-a; 27 dy[0]=dy[3]=dx[4]=dx[7]=-b; 28 for(int i=1;i<=r;++i)scanf("%s",s[i]+1); 29 for(int i=1;i<=r;++i)for(int j=1;j<=c;++j)o[i][j]=++T;++T; 30 for(int i=1,x,y;i<=n;++i)scanf("%d%d",&x,&y),con(0,o[x][y],0); 31 for(int i=1,x,y;i<=n;++i)scanf("%d%d",&x,&y),con(o[x][y],T,0); 32 for(int x=1;x<=r;++x)for(int y=1;y<=c;++y)if(s[x][y]=='.') 33 for(int i=0,X,Y;X=x+dx[i],Y=y+dy[i],i<8;++i)if(X>0&&Y>0&&X<=r&&Y<=c&&s[X][Y]=='.') 34 con(o[x][y],o[X][Y],1,n); 35 while(BFS())MF+=dfs(0,n);printf("%d",MF==n?ans:-1); 36 }
T2:景中人
大意:平面上$n$个点,要求你用尽量少的面积$\le s$的长宽任意的矩形覆盖所有点。$n\le 100,T\le 10$
坐标没啥好说的,直接排序就是了。(当然也可以离散化
然后设$f(i,j,k)$表示横坐标排名$[i,j]$的所有点且纵坐标大于等于$k$的所有点,至少需要几个矩形能覆盖完。
记搜:转移比较简单:要么枚举一个分界线,没有任意一个矩形跨过分界线,否则就用一个横坐标覆盖整个区间,纵坐标尽量大的矩形。
理论复杂度$O(Tn^4)$。然而完全跑不满。代码长度和时间都非常短。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct pts{ int x,y; friend bool operator<(pts a,pts b){return a.x<b.x;}}ps[111]; 4 int dp[111][111][111],n,s,t,Y[111]; 5 int f(int l,int r,int h){ 6 while(l<=r&&ps[l].y<Y[h])l++; 7 while(l<=r&&ps[r].y<Y[h])r--; 8 if(l>r)return 0; 9 if(l==r)return 1; 10 if(dp[l][r][h])return dp[l][r][h]; 11 dp[l][r][h]=r-l+1; 12 for(int y=l;y<r;++y)dp[l][r][h]=min(dp[l][r][h],f(l,y,h)+f(y+1,r,h)); 13 return dp[l][r][h]=min(dp[l][r][h],1+f(l,r,upper_bound(Y+1,Y+1+n,s/max(ps[r].x-ps[l].x,1))-Y)); 14 } 15 int main(){cin>>t;while(t--){ 16 cin>>n>>s;memset(dp,0,sizeof dp); 17 for(int i=1;i<=n;++i)scanf("%d%d",&ps[i].x,&ps[i].y); 18 sort(ps+1,ps+1+n); 19 for(int i=1;i<=n;++i)Y[i]=ps[i].y; 20 sort(Y+1,Y+1+n);Y[n+1]=1000000007; 21 cout<<f(1,n,1)<<endl; 22 }}
T3:钦点
大意:$n$个带权点,$gcd$为合数的点对会连边,要求删掉一个点之后最小化最大联通块大小。$n \le 10^5,a_i \le 10^7,T \le 10$
线筛预处理,然后就可以$O(log)$分解质因数。
然后对于每个数我们可以$O(log^2)$的枚举它的所有含两个质因子的约数。
所有含有相同的这样的约数的点形成一个完全图,然而这道题里我们只需要形成一个点双即可,那么只需要一个环。
每个点向上一次出现这个点的连边,然后第一次向最后一次连边,就可以了。
原图有若干联通块,我们只在意最大的和次大的/
然后只要求出最大的联通块中每个点去掉之后分成了怎样的几个联通块与次大的取$max$。跑个$tarjan$类似物就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define S 100005 4 #define A 10000007 5 int p[A],pc,lp[A],t,n,lst[S],vc,o[A],fir[A],v[A],dfn[S],low[S],sz[S],al[S],mx1,mx2,rt,ans,tim; bool np[A]; 6 vector<int>s[S]; 7 void dfs(int p){ 8 al[p]=1;sz[p]=1; 9 for(int i=0;i<s[p].size();++i)if(!al[s[p][i]])dfs(s[p][i]),sz[p]+=sz[s[p][i]]; 10 } 11 void DFS(int p){ 12 dfn[p]=low[p]=++tim; int mx=0,r=sz[rt]-1; 13 for(int i=0,y;y=i<s[p].size()?s[p][i]:0;++i) 14 if(!dfn[y]){ 15 DFS(y),low[p]=min(low[y],low[p]); 16 if(low[y]>=dfn[p])r-=sz[y],mx=max(mx,sz[y]); 17 }else low[p]=min(low[p],dfn[y]); 18 ans=min(ans,max(r,mx)); 19 } 20 void link(int a,int b){if(a!=b)s[a].push_back(b),s[b].push_back(a);} 21 int main(){ 22 for(int i=2;i<A;++i){ 23 if(!np[i])p[++pc]=i,lp[i]=i; 24 for(int j=1;i*p[j]<A;++j){ 25 np[i*p[j]]=1; lp[i*p[j]]=p[j]; 26 if(i%p[j]==0)break; 27 } 28 }cin>>t;while(t--){cin>>n; 29 for(int z=1,x;z<=n;++z){ 30 scanf("%d",&x);pc=0; 31 while(x^1)p[++pc]=lp[x],x/=lp[x]; p[pc+1]=0; 32 for(int i=1;i<=pc;++i)for(int j=i+1,y;y=o[p[i]*p[j]],j<=pc;++j) 33 if(!y)o[v[++vc]=p[i]*p[j]]=vc,fir[vc]=lst[vc]=z; 34 else link(lst[y],z),lst[y]=z; 35 }for(int i=1;i<=vc;++i)link(fir[i],lst[i]); 36 for(int i=1;i<=n;++i)if(!al[i]){ 37 dfs(i); 38 if(sz[i]>mx2)if(sz[i]>mx1)mx2=mx1,mx1=sz[i],rt=i;else mx2=sz[i]; 39 } 40 if(mx1==mx2)printf("%d\n",mx1); 41 else ans=n,DFS(rt),printf("%d\n",max(ans,mx2)); 42 for(int i=1;i<=n;++i)s[i].clear(),dfn[i]=low[i]=sz[i]=al[i]=0; 43 for(int i=1;i<=vc;++i)o[v[i]]=0; mx1=mx2=vc=0; 44 } 45 }