• 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
    ",-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
    ",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
    ",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
    ",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
    ",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
    ",ans);
        return 0;
    }
    View Code

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

  • 相关阅读:
    mysql怎么在已建好的表中添加自增序列
    IDEA报错: Invalid bound statement (not found): com.test.mapper.UserMapper.selectByPrimaryKey(转发:https://www.cnblogs.com/woshimrf/p/5138726.html)
    Windows下重置MySQL密码(最开始是因为Access denied for user 'root'@'localhost'这个原因,无法登陆 'root'@'localhost')
    数组逆转
    选择、插入、冒泡排序
    线性单链表
    顺序队列
    栈的应用----表达式求值
    顺序表的应用---若瑟夫问题
    顺序栈
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10354915.html
Copyright © 2020-2023  润新知