Gym-101673 :East Central North America Regional Contest (ECNA 2017)(寒假自训第8场)
A .Abstract Art
题意:求多个多边形的面积并。
思路:模板题。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const double inf=1e200; const double eps=1e-12; const double pi=4*atan(1.0); int dcmp(double x){ return fabs(x)<eps?0:(x<0?-1:1);} struct point{ double x,y; point(double a=0,double b=0):x(a),y(b){} }; 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);} bool operator ==(const point& a,const point& b){ return fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps; } 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 det(point O,point A,point B){ return det(A-O,B-O);} double length(point A){ return sqrt(dot(A,A));} double area(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; } 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); } vector<point>pp[110]; 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++]=make_pair(0,0); s[m++]=make_pair(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++]=make_pair(seg(c,a,b),1); s[m++]=make_pair(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++]=make_pair(s1/(s1-s2),1); else if(c1<0&&c2>=0) s[m++]=make_pair(s1/(s1-s2),-1); } } } } sort(s,s+m); double pre=min(max(s[0].first,0.0),1.0),now,sum=0; int cov=s[0].second; for(int j=1;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; } int main() { int N,M,i,j; point tp; scanf("%d",&N); for(i=0;i<N;i++){ scanf("%d",&M); for(j=0;j<M;j++){ scanf("%lf%lf",&tp.x,&tp.y); pp[i].push_back(tp); } } double t1=0,t2=polyunion(pp,N); for(i=0;i<N;i++) t1+=area(pp[i]); printf("%f %f\n",-t1,-t2); return 0; }
B .Craters
题意:给定N个圆,让你用最小的周长把这些圆包起来,且满足到圆的最近距离不小于10.
思路:把每个圆的半径增加10,然后等分1000份,然后求凸包即可。
#include<bits/stdc++.h> #define mp make_pair using namespace std; typedef long long ll; const double inf=1e200; const double eps=1e-6; const double pi=4*atan(1.0); int dcmp(double x){ return fabs(x)<eps?0:(x<0?-1:1);} struct point{ double x,y; point(double a=0,double b=0):x(a),y(b){} }; 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 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 area(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; } 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); } bool cmp(point a,point b){ return a.x==b.x?a.y<b.y:a.x<b.x; } void convexhull(point *a,int n,point *ch,int &top) { 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]; } } point ch[2000000],p[2000000]; int main() { int N,i,j,tot=0,top; double ans,one=pi/2500,x,y,r; scanf("%d",&N); for(i=1;i<=N;i++){ scanf("%lf%lf%lf",&x,&y,&r); r+=10; for(j=1;j<=5000;j++){ tot++; p[tot].x=x+r*cos(one*j); p[tot].y=y+r*sin(one*j); } } convexhull(p,tot,ch,top); for(i=1;i<top;i++) ans+=length(ch[i]-ch[i+1]); printf("%.10lf\n",ans); return 0; }
C .DRM Messages
题意:字符串操作模拟。
思路:模拟。
#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; char c[maxn]; void solve(int L,int R) { int sum=0; rep(i,L,R) sum+=c[i]-'A'; sum%=26; rep(i,L,R) c[i]=(c[i]-'A'+sum+26)%26+'A'; } int main() { int N; scanf("%s",c+1); N=strlen(c+1); solve(1,N/2); solve(N/2+1,N); rep(i,1,N/2){ c[i]=(c[i]-'A'+(c[i+N/2]-'A')+26)%26+'A'; } rep(i,1,N/2) putchar(c[i]); return 0; }
D .Game of Throwns
题意:模拟题。
思路:模拟。
#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 q[maxn],tot; int read() { int x=0,F=1; char c=getchar(); while(c!='-'&&c!='u'&&!(c>='0'&&c<='9')) c=getchar(); if(c=='-') F=-1,c=getchar(); else if(c=='u') { rep(i,1,3) c=getchar(); return maxn; } while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); return F*x; } int main() { int N,K,x,P=0; scanf("%d%d",&N,&K); rep(i,1,K) { x=read(); if(x==maxn) { x=read(); tot-=x; } else q[++tot]=x; } rep(i,1,tot) P=((P+q[i])%N+N)%N; printf("%d\n",P); return 0; }
E .Is-A? Has-A? Who Knowz-A?
题意:题意可能没有解释清楚。N个名字,M个传递关系,Q次询问,反正就是有两种传递关系,is和has,A(has or is)->B; B->C; C->D;像这样的传递关系,假如全部都是is,则A可以推出isD;否则可以推出A has D。N<=500。
思路:因为N<500,直接DFS即可,复杂度O(N^3);注意自己和自己有is关系,但是没有has关系。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=510; int dis[maxn][maxn][2],tot; struct in{ int x,y,opt; in(){} in(int xx,int yy,int oo):x(xx),y(yy),opt(oo){} }; queue<in>q; map<string,int>mp; map<int,string>F; void name(string s){ if(mp.find(s)==mp.end()) { mp[s]=++tot; F[tot]=s; } } void DFS() { while(!q.empty()){ int x=q.front().x,y=q.front().y,op=q.front().opt; q.pop(); //cout<<":"<<F[x]<<" "<<F[y]<<" "<<op<<endl; dis[x][y][op]=1; for(int i=1;i<=tot;i++){ if(!dis[x][i][0]&&dis[y][i][0]){ dis[x][i][0]=1; q.push(in(x,i,0)); } if(!dis[x][i][0]&&dis[y][i][1]&&op==0){ dis[x][i][0]=1; q.push(in(x,i,0)); } if(!dis[x][i][1]&&dis[y][i][1]&&op==1){ dis[x][i][1]=1; q.push(in(x,i,1)); } } } } int main() { int N,M,u,v,Ca=0; string A,B,C; scanf("%d%d",&N,&M); rep(i,1,N){ cin>>A>>B>>C; name(A); name(C); if(B[0]=='i') q.push(in(mp[A],mp[C],1)),dis[mp[A]][mp[C]][1]=1; else q.push(in(mp[A],mp[C],0)),dis[mp[A]][mp[C]][0]=1; } DFS(); rep(i,1,M){ cin>>A>>B>>C; printf("Query %d: ",++Ca); if(A==C&&B[0]=='i') {puts("true"); continue;} u=mp[A]; v=mp[C]; if(B[0]=='i') { if(dis[u][v][1]) puts("true"); else puts("false"); } else { if(dis[u][v][0]) puts("true"); else puts("false"); } } return 0; }
F .Keeping On Track
题意:给定一棵树,问删去一个点后,不连通的点最对有多少,在此基础上加一条边可以最多让多少对点对恢复连通。
思路:就是dfs一次,然后看所有儿子和父亲之上的连通块的大小; 第二问取最大的两个连通块连通即可。
#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=20010; int Laxt[maxn],Next[maxn],To[maxn]; int sz[maxn],q[maxn],cnt,ans,fcy,tot,N; void add(int u,int v) { Next[++cnt]=Laxt[u];Laxt[u]=cnt;To[cnt]=v; } void dfs(int u,int f) { sz[u]=1; for(int i=Laxt[u];i;i=Next[i]){ if(To[i]!=f){ dfs(To[i],u); sz[u]+=sz[To[i]]; } } tot=0; q[++tot]=N+1-sz[u]; for(int i=Laxt[u];i;i=Next[i]) if(To[i]!=f) q[++tot]=sz[To[i]]; sort(q+1,q+tot+1); int sum=0,tmp=0; rep(i,1,tot) sum+=q[i]; rep(i,1,tot) tmp+=(sum-q[i])*q[i]; tmp/=2; if(tmp>ans) ans=tmp,fcy=q[tot]*q[tot-1]; else if(tmp==ans) fcy=max(fcy,q[tot]*q[tot-1]); } int main() { int u,v; scanf("%d",&N); rep(i,1,N) { scanf("%d%d",&u,&v); add(u,v); add(v,u); } dfs(0,-1); printf("%d %d\n",ans,ans-fcy); return 0; }
G .A Question of Ingestion
题意:一个人开始的饭量是M,如果今天吃饭了,第二天的饭量变为今天的2/3;如果今天不吃,第二天的饭量和昨天饭量一样(即恢复); 如果连续两天不吃,则第三天的饭量恢复到M。 现在给出N天的食物量, 问怎么吃可以迟到最多的食物。
思路:DP即可,dp[i][j]表示第i天的时候是连续第j天吃饭的最大食物量。
#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=210; int a[maxn],f[maxn],dp[maxn][maxn],ans; int main() { int N,M; scanf("%d%d",&N,&M); f[1]=M; rep(i,1,N) scanf("%d",&a[i]); rep(i,2,N) f[i]=f[i-1]*2/3; rep(i,1,N){ rep(j,1,i){ dp[i][j]=max(dp[i][j],dp[i-1][j-1]+min(f[j],a[i])); if(i>1)dp[i][j]=max(dp[i][j],dp[i-2][j]+min(f[j],a[i])); if(i>2)dp[i][1]=max(dp[i][1],dp[i-3][j]+min(f[1],a[i])); } } rep(i,1,N) ans=max(ans,dp[N][i]); printf("%d\n",ans); return 0; }
H .Sheba's Amoebas
题意:问有几个连通块。
思路:DFS或者并查集即可。
#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=210; char c[maxn][maxn]; int fa[maxn*maxn],ans,N,M; int x[8]={1,1,1,-1,-1,-1,0,0}; int y[8]={-1,0,1,-1,0,1,-1,1}; int find(int x){ if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void merge(int u,int v) { int fu=find(u),fv=find(v); if(fu!=fv) fa[fu]=fv; } int main() { scanf("%d%d",&N,&M); rep(i,1,N*M) fa[i]=i; rep(i,1,N) scanf("%s",c[i]+1); rep(i,1,N) rep(j,1,M){ if(c[i][j]=='#'){ rep(k,0,7){ if(i+x[k]>=1&&i+x[k]<=N&&j+y[k]>=1&&j+y[k]<=M&&c[i+x[k]][j+y[k]]=='#'){ merge((i-1)*M+j,(i+x[k]-1)*M+j+y[k]); } } } } rep(i,1,N) rep(j,1,M){ if(c[i][j]!='#') continue; int t=(i-1)*M+j; if(find(t)==t) ans++; } printf("%d\n",ans); return 0; }
太累了,后面了两个题先鸽了
It is your time to fight!