Gym.102006:Syrian Collegiate Programming Contest(寒假自训第11场)
学习了“叙利亚”这个单词;比较温和的一场;几何的板子eps太小了,坑了几发。
A .Hello SCPC 2018!
题意:给定一个排列,问它是否满足,前面4个是有序的,而且前面4个比后面的都小。
思路:数据比较小,可以暴力,也可以用前面4个的最大值和后面的数字的最小值比较。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; int a[maxn]; int main() { int T,N; scanf("%d",&T); while(T--){ rep(i,1,12) scanf("%d",&a[i]); bool F=true; rep(i,1,3) if(a[i]>a[i+1]) F=false; rep(i,1,4) rep(j,5,12) if(a[i]>a[j]) F=false; if(F) puts("yes"); else puts("no"); } return 0; }
B .Binary Hamming
题意:给定两个01串,让你重排,使得对应位置不同的个数最多。
思路:有点像那个石头剪刀布的题,答案是min(A的石头,B的剪刀)+min(A的布,B的石头)+min(A的剪刀,B的布)。 所以这个题就是min(A的0,B的1)+min(A的1,B的0);
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; char c[maxn]; int main() { int T,N; scanf("%d",&T); while(T--){ int A,B,C,D; scanf("%d",&N); A=B=C=D=0; scanf("%s",c+1); rep(i,1,N) if(c[i]=='1') A++; else B++; scanf("%s",c+1); rep(i,1,N) if(c[i]=='1') C++; else D++; printf("%d\n",min(A,D)+min(B,C)); } return 0; }
C.Portals
题意:给定N个格子...问,至少使多少格子阻断,使得个s和t不连通。
思路:大讨论,自己写挂了。 by罗。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=998244353; const int maxn=2e6+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; char s[maxn]; int dx[2]={1,-1}; int n; int S,T; int dfs(int x,int i){ if(x==n+1)return 0; if(x==0)return 0; if(s[x]=='#')return 0; if(s[x]=='o')return 1; if(s[x]=='s'||s[x]=='e')return 1; return dfs(x+dx[i],i); } int main() { freopen("portals.in","r",stdin); int t; cin>>t; while(t--){ cin>>n; for(int i=0;i<=n+10;i++)s[i]='#'; cin>>s+1; int len=strlen(s+1); for(int i=1;i<=n;i++){ if(s[i]=='s')S=i; if(s[i]=='e')T=i; } if(abs(S-T)==1){ cout<<"-1"<<endl;continue; } if((s[S-1]=='o'||s[S+1]=='o')&&(s[T-1]=='0'||s[T+1]=='o')){ cout<<"-1"<<endl;continue; } int neds=dfs(S+1,0)+dfs(S-1,1); int nedt=dfs(T+1,0)+dfs(T-1,1); int ans=1e9; if(s[S-1]=='o'||s[S+1]=='o')neds=1e9; if(s[T-1]=='o'||s[T+1]=='o')nedt=1e9; ans=min(neds,nedt); if(ans==1e9)cout<<-1<<endl; else cout<<ans<<endl; } return 0; }
D .Carnival Slots
题意:给定N*M的矩阵,现在1到M分别有numi个球向下掉,一个球掉到第j列的收益的moneyj; 一个格子如果是‘.',那么它只能向下掉, 否则可以向下,左下,右下掉。问最大收益是多少。
思路:和数字三角形的那个dp有点像,从下到上跟新dp值,表示单个球经过它能向下到达的最大收益是多少。 主要是考虑到球和球是独立的,所以不用想太多。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=510; ll dp[maxn][maxn],num[maxn],ans;int N,M; char c[maxn][maxn]; void solve() { for(int i=N;i>=1;i--){ rep(j,1,M){ dp[i][j]=dp[i+1][j]; if(c[i][j]!='.'){ if(j-1>=1) dp[i][j]=max(dp[i][j],dp[i+1][j-1]); if(j+1<=M) dp[i][j]=max(dp[i][j],dp[i+1][j+1]); } } } } int main() { int T; scanf("%d",&T); while(T--){ ans=0; scanf("%d%d",&N,&M); rep(i,1,M) scanf("%lld",&num[i]); rep(i,1,N) scanf("%s",c[i]+1); rep(i,1,M) scanf("%lld",&dp[N+1][i]); solve(); rep(i,1,M) ans+=num[i]*dp[1][i]; printf("%lld\n",ans); } return 0; }
G .Is Topo Logical?
题意:
思路:
比赛的时候看错题意了,样例没看懂,感觉可以做。待会补。
H .Bugged System
题意:反正就是问是否有向图存在欧拉回路。
思路:入度=出度。
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; int ind[maxn],oud[maxn],L[maxn]; ll ans; int main() { int T,N,M,x,y; scanf("%d",&T); while(T--){ ans=0; scanf("%d%d",&N,&M); rep(i,1,N) scanf("%d",&L[i]),ind[i]=oud[i]=0; rep(i,1,M) { scanf("%d%d",&x,&y); ans+=abs(L[x]-L[y]); ind[y]++; oud[x]++; } rep(i,1,N) if(ind[i]!=oud[i]) ans=-1; printf("%lld\n",ans); } return 0; }
I. Rise of the Robots
题意:给定一个大圆,起点未知,然后给你一个小圆的路径,让你求一个起点,使得它走到的点都在大圆里。 一定有解。
思路:一定有解,那么我们可以不考虑大圆和小圆,我们只关心小圆的圆心即可。我们求个这个路径的圆心,满足以它的相反数为为起点,一定可以满足题意。
所以就是求最小圆覆盖,对应的圆心。 可以用模拟退火贪心,也可以三分套三分(我不会)。
误区:最开始我也是想的去求这样一个中心,但是我想的是用旋转卡壳去求最长的边对应的中心,这样是错的。
#include<bits/stdc++.h> using namespace std; #define mp make_pair typedef long long ll; const double inf=1e200; const double eps=1e-8; const double pi=4*atan(1.0); struct point{ double x,y; point(double a=0,double b=0):x(a),y(b){} }; int dcmp(double x){ return fabs(x)<eps?0:(x<0?-1:1);} point operator +(point A,point B) { return point(A.x+B.x,A.y+B.y);} point operator -(point A,point B) { return point(A.x-B.x,A.y-B.y);} point operator *(point A,double p){ return point(A.x*p,A.y*p);} point operator /(point A,double p){ return point(A.x/p,A.y/p);} point rotate(point A,double rad){ return point(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad)); } bool operator ==(const point& a,const point& b) { return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double dot(point A,point B){ return A.x*B.x+A.y*B.y;} double det(point A,point B){ return A.x*B.y-A.y*B.x;} double dot(point O,point A,point B){ return dot(A-O,B-O);} double det(point O,point A,point B){ return det(A-O,B-O);} double length(point A){ return sqrt(dot(A,A));} double angle(point A,point B){ return acos(dot(A,B)/length(A)/length(B));} double distoline(point P,point A,point B) { //点到直线距离 point v1=B-A,v2=P-A; return fabs(det(v1,v2)/length(v1)); } double distoseg(point P,point A,point B) { //点到线段距离 if(A==B) return length(P-A); point v1=B-A,v2=P-A,v3=P-B; if(dcmp(dot(v1,v2))<0) return length(v2); else if(dcmp(dot(v1,v3))>0) return length(v3); return fabs(det(v1,v2)/length(v1)); } double Ployarea(vector<point>p) { //多边形面积 double ans=0; int sz=p.size(); for(int i=1;i<sz-1;i++) ans+=det(p[i]-p[0],p[i+1]-p[0]); return ans/2.0; } bool SegmentProperIntersection(point a1,point a2,point b1,point b2) { //规范相交 double c1=det(a2-a1,b1-a1),c2=det(a2-a1,b2-a1); double c3=det(b2-b1,a1-b1),c4=det(b2-b1,a2-b1); return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0; } bool isPointOnSegment(point p,point a1,point a2) { //点是否在线段上 return dcmp(det(a1-p,a2-p)==0&&dcmp(dot(a1-p,a2-p))<0); } int isPointInPolygon(point p,vector<point>poly) { //判断点与多边形的位置关系 int wn=0,sz=poly.size(); for(int i=0;i<sz;i++){ //在边上 if(isPointOnSegment(p,poly[i],poly[(i+1)%sz])) return -1; int k=dcmp(det(poly[(i+1)%sz]-poly[i],p-poly[i])); int d1=dcmp(poly[i].y-p.y); int d2=dcmp(poly[(i+1)%sz].y-p.y); if(k>0&&d1<=0&&d2>0) wn++; if(k<0&&d2<=0&&d1>0) wn--; } if(wn!=0) return 1;//内部 return 0; //外部 } double seg(point O,point A,point B){ if(dcmp(B.x-A.x)==0) return (O.y-A.y)/(B.y-A.y); return (O.x-A.x)/(B.x-A.x); } pair<double,int>s[110*60]; double polyunion(vector<point>*p,int N){ //有多个才加*,单个不加,有改变的加& //求多边形面积并 double res=0; for(int i=0;i<N;i++){ int sz=p[i].size(); for(int j=0;j<sz;j++){ int m=0; s[++m]=mp(0,0); s[++m]=mp(1,0); point a=p[i][j],b=p[i][(j+1)%sz]; for(int k=0;k<N;k++){ if(i!=k){ int sz2=p[k].size(); for(int ii=0;ii<sz2;ii++){ point c=p[k][ii],d=p[k][(ii+1)%sz2]; int c1=dcmp(det(b-a,c-a)); int c2=dcmp(det(b-a,d-a)); if(c1==0&&c2==0){ if(dcmp(dot(b-a,d-c))){ s[++m]=mp(seg(c,a,b),1); s[++m]=mp(seg(c,a,b),-1); } } else{ double s1=det(d-c,a-c); double s2=det(d-c,b-c); if(c1>=0&&c2<0) s[++m]=mp(s1/(s1-s2),1); else if(c1<0&&c2>=0) s[++m]=mp(s1/(s1-s2),-1); } } } } sort(s+1,s+m+1); double pre=min(max(s[1].first,0.0),1.0),now,sum=0; int cov=s[0].second; for(int j=2;j<=m;j++){ now=min(max(s[j].first,0.0),1.0); if(!cov) sum+=now-pre; cov+=s[j].second; pre=now; } res+=det(a,b)*sum; } } return -(res/2); } point jiaopoint(point p,point v,point q,point w) { //p+tv q+tw,点加向量表示直线,求直线交点 point u=p-q; double t=det(w,u)/det(v,w); return p+v*t; } point GetCirPoint(point a,point b,point c) { point p=(a+b)/2; //ad中点 point q=(a+c)/2; //ac中点 point v=rotate(b-a,pi/2.0),w=rotate(c-a,pi/2.0); //中垂线的方向向量 if (dcmp(length(det(v,w)))==0) //平行 { if(dcmp(length(a-b)+length(b-c)-length(a-c))==0) return (a+c)/2; if(dcmp(length(b-a)+length(a-c)-length(b-c))==0) return (b+c)/2; if(dcmp(length(a-c)+length(c-b)-length(a-b))==0) return (a+b)/2; } return jiaopoint(p,v,q,w); } point MinCircular(point *P,int n) { //最小圆覆盖 ,看起来是O(N^3),期望复杂度为O(N) random_shuffle(P+1,P+n+1); //随机化 point c=P[1]; double r=0; //c 圆心,,//r 半径 for (int i=2;i<=n;i++) if (dcmp(length(c-P[i])-r)>0) //不在圆内 { c=P[i],r=0; for (int j=1;j<i;j++) if (dcmp(length(c-P[j])-r)>0) { c=(P[i]+P[j])/2.0; r=length(c-P[i]); for (int k=1;k<j;k++) if (dcmp(length(c-P[k])-r)>0) { c=GetCirPoint(P[i],P[j],P[k]); r=length(c-P[i]); } } } //cout<<r<<":"<<c.x<<" "<<c.y<<endl; return c; } const int maxn=400010; bool cmp(point a,point b){ return a.x==b.x?a.y<b.y:a.x<b.x; } point f[maxn],c[maxn],ch[maxn]; void convexhull(point *a,int n,int &top) { //水平序的Andrew算法求凸包。 sort(a+1,a+n+1,cmp); top=0; for(int i=1;i<=n;i++){ //求下凸包 while(top>=2&&det(ch[top-1],ch[top],a[i])<=0) top--; ch[++top]=a[i]; } int ttop=top; for(int i=n-1;i>=1;i--){ //求上凸包 while(top>ttop&&det(ch[top-1],ch[top],a[i])<=0) top--; ch[++top]=a[i]; } } void P(double x) { //if(fabs(x)<0.000001) puts("0.00000000"); else printf("%.9lf",x); } int main() { freopen("robots.in","r",stdin); int T,N,tot,top; scanf("%d",&T); while(T--){ double R,r; scanf("%d%lf%lf",&N,&R,&r); double x=0.0,y=0.0; f[tot=1]=point(x,y); for(int i=2;i<=N+1;i++){ scanf("%lf%lf",&f[i].x,&f[i].y); x+=f[i].x; y+=f[i].y; f[++tot]=point(x,y); } convexhull(f,tot,top); point res=MinCircular(ch,top); //cout<<res.x<<" "<<res.y<<endl; //res.x=-res.x; res.y=-res.y;P(res.x); putchar(' '); P(res.y); putchar('\n'); printf("%.6lf %.6lf\n",-res.x,-res.y); } return 0; }
K .Tourists' Tour
题意:给定N个数,每个位置分别和左右第一个大于它的值的位置连边。 然后给这些位置然后,有边相邻的两个点的颜色不能相同,问最小的颜色数,以及输出一个方案。
思路:首先猜到颜色数应该很小,所以最后可以用mex来求颜色。 我们可以用单调队列O(N)或者线段树O(NlogN)求边。 那么现在就是需要按一定顺序来染色即可。
我们可以把边变为有向边,即只从值大的连向小的。 那么它一定是个DAG,我们就可以topo了。
不难证明:颜色数=max(入度+1); 而入度最大为2,所以颜色最大值是3。
#include<bits/stdc++.h> #define rep2(i,a,b) for(int i=a;i>=b;i--) #define rep(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int maxn=1000010; int Next[maxn<<1],Laxt[maxn<<1],To[maxn<<1],ind[maxn]; int a[maxn],q[maxn],vis[maxn],col[maxn],head,tail,ans,cnt,top; vector<int>G[maxn]; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; ind[v]++; G[v].push_back(u); } int main() { int T,N; freopen("tour.in","r",stdin); scanf("%d",&T); while(T--) { scanf("%d",&N); head=tail=ans=cnt=0; rep(i,1,N) Laxt[i]=ind[i]=vis[i]=0,G[i].clear(); rep(i,1,N) scanf("%d",&a[i]); top=0; rep(i,1,N){ while(top&&a[i]>=a[q[top]]) top--; if(top) add(q[top],i); q[++top]=i; } top=0; rep2(i,N,1){ while(top&&a[i]>=a[q[top]]) top--; if(top) add(q[top],i); q[++top]=i; } rep(i,1,N) if(!ind[i]) q[++head]=i; while(tail<head){ int u=q[++tail],v; for(int i=Laxt[u];i;i=Next[i]){ v=To[i]; ind[v]--; if(!ind[v]) q[++head]=v; } for(int i=0;i<G[u].size();i++){ vis[col[G[u][i]]]=u; } rep(i,1,4) if(vis[i]!=u) {col[u]=i; break;} ans=max(ans,col[u]); } printf("%d\n",ans); rep(i,1,N-1) printf("%d ",col[i]); printf("%d\n",col[N]); } }