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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

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;
}
View Code

 

太累了,后面了两个题先鸽了

posted @ 2019-02-07 16:32  nimphy  阅读(177)  评论(0编辑  收藏