zoukankan      html  css  js  c++  java
  • 2019 ICPC Malaysia National 题解

    A - Mental Rotation(模拟)

    思路:

    只要发现旋转的规律就好了

    就是向右旋转的时候,矩阵整体旋转,之后里面的图形成为逆时针旋转$90°$的图形

    #include<iostream>
    #include<algorithm>
    #include<cstring>
     using namespace std;
     const int maxn=5005;
    char a[maxn][maxn], a1[maxn][maxn], str[maxn];
    int n;
    void Right()
    {
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++){
                if(a[i][j]=='^') a1[j][n-i+1]='>';
                else if(a[i][j]=='v') a1[j][n-i+1]='<';
                else if(a[i][j]=='<') a1[j][n-i+1]='^';
                else if(a[i][j]=='>') a1[j][n-i+1]='v';
                else a1[j][n-i+1] ='.';
            }
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                a[i][j]=a1[i][j];
    }
    int main()
    {
        int l, r;
        scanf("%d%s",&n,str);
        for(int i=1; i<=n; i++) scanf("%s", a[i]+1);
        l=0;r=0;
        for(int i=0; i<strlen(str); i++){
            if(str[i]=='L') l++;
            else r++;
        }
        l%=4;
        r%=4;
        r=(r-l+4)%4;
        while(r--) Right();
        for(int i=1; i<=n; i++)
            printf("%s
    ", a[i]+1);
        return 0;
    }
    View Code

    B - SpongeBob SquarePants (签到题)

    #include<iostream>
    #include<algorithm>
     using namespace std;
     int main()
     {
         int t;
         cin>>t;
         while(t--){
             int a,b;
             cin>>a>>b;
             if(a==b) cout<<"YES"<<endl;
             else cout<<"NO"<<endl;
         }
     }
    View Code

    C - I Don't Want To Pay For The Late Jar!(签到题)

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    int main() {
        int t,n,m,kase=0;
        scanf("%d",&t);
        while(t--){
            int max_=-inf;
            scanf("%d%d",&n,&m);
            for (int i=0;i<n;i++) {
                int u,v;
                scanf("%d%d",&u,&v);
                if (v<=m) max_=max(max_, u);
                else max_=max(max_,u-(v-m));
            }
            printf("Case #%d: %d
    ",++kase,max_);
        }
        return 0;
    }
    View Code

    D - Optimal Slots(01背包)

    思路:

    转化下题意题意就是一个$01$背包问题

    但是要求记录路径,并且要求答案相同时去最前面的方案 (这个限制我们只要从后往前枚举,遇到大小相同的方案就替代即可)

    用$path[i][j]$表示到第$i$个数时容量为$j$时的选择($0$不选,$1$选),最后把路径输出就行了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int dp[10005];
    bool path[105][10005];
    int c[10005],w[10005];
    int main()
    {
        int N,V;
        while (cin>>V&&V){
            cin>>N;
            memset(path,0,sizeof(path));
            memset(dp,0,sizeof(dp));
            for (int i=1;i<=N;++i){
                cin>>c[i];
                w[i]=c[i];
            }
            for(int i=N;i>=1;--i){
                for(int j=V;j>=c[i];--j){
                    if(dp[j]<=dp[j-c[i]]+w[i]){
                        dp[j]=dp[j-c[i]]+w[i];
                        path[i][j] = 1;
                    }
                }
            } 
            for(int i=1,j=V;i<=N&&j>0;i++){
                if(path[i][j]){
                    printf("%d ",w[i]);
                    j-=c[i];
                }
            }
            cout<<dp[V]<<endl;
        }
        return 0;
    }
    View Code

    E - Military Class(状压DP)

    思路:

    由于$e$很小,我们可以考虑用二进制来表示第$i$号士兵可以匹配的士兵的状态

    用$DP[i][j]$来表示第$i$号士兵,附近的士兵匹配状态为$j$时的方案数

    我们假设$e=2$,并且状态$j$的二进制表示为$11010$,我们要考虑每个$1$是从哪里转移过来的

    我们考虑从右到左的第二位,那么他可能从第$i-1$位士兵的$01100$与$11100$状态转移而来,所以我们可以通过考虑每个$1$是从哪里转移过来从而得到该状态的方案数

    最后答案为就$dp[i][j] (j=11100)$

    #include<iostream>
    #include<algorithm>
     using namespace std;
     const int maxn=2005;
     const int mod=1e9+7;
     int mp[maxn][maxn],dp[maxn][maxn];
     int main()
     {
         int n,e,m,x,y;
         cin>>n>>e>>m;
         for(int i=1;i<=m;i++){
             cin>>x>>y;
             mp[x][y]=1;
         }
        for(int i=0;i<=e;i++)
            if(!mp[i][1]) dp[1][1<<i]=1;
        for(int i=2;i<=n;i++){
            for(int j=0;j<(1<<2*e+1);j++){
                for(int k=0;k<2*e+1;k++){
                    if(i+e-k<1||i+e-k>n) continue;
                    if(mp[i+e-k][i]) continue;
                    if(j&(1<<k)){
                        dp[i][j]=(dp[i][j]+dp[i-1][(j^(1<<k))>>1])%mod;
                        dp[i][j]=(dp[i][j]+dp[i-1][((j^(1<<k))>>1)|(1<<2*e)])%mod;
                    }
                }    
            }
        }
        int temp=(1<<(2*e+1))-1;
        for(int i=0;i<e;i++) temp-=(1<<i);
        cout<<dp[n][temp]%mod;
     }
    View Code

    F - Ali The Multi-billionaire(待补)

    G - Are You Safe?(二维凸包)

    思路:

    二维凸包裸题,直接利用叉积判断点是否在凸包内即可

    #include <bits/stdc++.h>
    using namespace std;
    double eps=1e-15;
    double pi=acos(-1);
    struct Point{
        double x,y;
        Point(double x=0,double y=0):x(x),y(y){}
    };
    typedef Point Vector;
    Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
    Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
    Vector operator * (Vector A,double B){return Vector(A.x*B,A.y*B);}
    Vector operator / (Vector A,double B){return Vector(A.x/B,A.y/B);}
    int dcmp(double x){
        if(fabs(x)<eps)return 0;
        else return x<0?-1:1;
    }
    bool operator < (const Point &a,const Point &b){
        return dcmp(a.x-b.x)<0||(dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)<0);
    }
    bool operator == (const Point &a,const Point &b){
        return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
    }
    double Cross(Vector A,Vector B){
        return A.x*B.y-A.y*B.x;
    }
    double Dot(Vector A,Vector B){
        return A.x*B.x+A.y*B.y;
    }
    Vector Rotate(Vector A,double rad){
        return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
    }
    int tubao(Point *p,int n,Point *ch){//求凸包,返回凸包数组的长度
        sort(p,p+n);
        int m=0;
        for(int i=0;i<n;i++){
            while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
            ch[m++]=p[i];
        }
        int k=m;
        for(int i=n-2;i>=0;i--){
            while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0)m--;
            ch[m++]=p[i];
        }
        if(n>1)m--;
        return m;
    }
    void readp(Point &A){
        scanf("%lf%lf",&A.x,&A.y);
    }
    bool onsegment(Point p,Point a1,Point a2){
        if(p==a1||p==a2)return false;
        return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
    }
    bool segmentcross(Point a1,Point a2,Point b1,Point b2){
        if(a1==b1||a1==b2||a2==b1||a2==b2)return true;
        double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
               c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
        return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
    }
    int intubao(Point *ch,int n,Point p){//判断p点是否在凸包内
        Vector A,B;
        int flag=0;
        for(int i=0;i<n;i++){
            A=ch[(i+1)%n]-ch[i];
            B=p-ch[i];
            /*if(onsegment(p,ch[i],ch[(i+1)%n])){//这题说了点在凸包上视为在凸包外
                flag=-1;
                break;
            }*/
            if(Cross(A,B)>0){
                flag++;
            }
        }
        if(flag==-1||flag==n)return 1;
        return 0;
    }
    int T,n,q,m;
    Point p1[10005],ch1[10005];
    struct node{
        double x,y;
    }g[1005];
    int main(){
        scanf("%d",&T);
        int kase=0;
        while(T--){
            scanf("%d%d",&n,&q);
            for(int i=0;i<n;i++){
                readp(p1[i]);
            }
            int m1=tubao(p1,n,ch1);
            for(int i=1;i<=q;i++){
                scanf("%lf%lf",&g[i].x,&g[i].y);
            }
            printf("Case %d
    ",++kase);
            for(int i=0;i<m1;i++){
                printf("%d %d
    ",(int)ch1[i].x,(int)ch1[i].y);
            }
            printf("%d %d
    ",(int)ch1[0].x,(int)ch1[0].y);
            for(int i=1;i<=q;i++){
                Point t;
                t.x=g[i].x;
                t.y=g[i].y;
                printf("%d %d ",(int)t.x,(int)t.y);
                if(intubao(ch1,m1,t))printf("is unsafe!
    ");
                else printf("is safe!
    ");
            }
            printf("
    ");
        }
    }
    View Code

    H - To Crash Or Not To Crash(签到题)

    #include<iostream>
    #include<algorithm>
     using namespace std;
     string s[4];
     int main()
     {
        for(int i=1;i<=3;i++) cin>>s[i];
        int flag=0;
        for(int i=1;i<=3;i++){
            for(int j=0;j<10;j++){
                if(s[i][j]=='=') flag=1;
                else if(flag&&s[i][j]!='.'){
                    cout<<s[i][j];
                    flag++;
                    break;
                }
            }
            if(flag==1){
                cout<<"You shall pass!!!";
                break;
            } 
            if(flag==2) break;
        }
        return 0;
      } 
    View Code

    I - Kitchen Plates(暴力)

    思路:

    总共就只有$2^{5}$种情况,我们全部枚举出来,再根据条件判断是否合法就行了

    也可以利用拓扑排序的思想来做

    #include<iostream>
    #include<algorithm>
     using namespace std;
     string s[6];
     int a[6],vis[6];
     void dfs(int k)
     {
         if(k>4){
             int flag=0;
             for(int i=1;i<=5;i++){
                 int x=s[i][0]-'A';
                 int y=s[i][2]-'A';
                 int pos1,pos2;
                 for(int j=0;j<5;j++){
                     if(a[j]==x) pos1=j;
                     if(a[j]==y) pos2=j;
                 }
                if(s[i][1]=='>'&&pos1>pos2) continue;
                if(s[i][1]=='<'&&pos1<pos2) continue;
                flag=1;
                break; 
             }
            if(!flag){
                for(int i=0;i<5;i++)
                    printf("%c",'A'+a[i]);
                exit(0);
            }
            return;
         }
         for(int i=0;i<5;i++){
             if(vis[i]==0){
                 a[k]=i;
                 vis[i]=1;
                dfs(k+1);
                 vis[i]=0;
             }
         }
        return;
     }
     int main()
     {
         for(int i=1;i<=5;i++) cin>>s[i];    
         dfs(0);
         cout<<"impossible";
         return 0;
      } 
    View Code

     

     

     

  • 相关阅读:
    2020-06-20 助教一周小结(第十七周)
    2020-06-14 助教一周小结(第十六周)
    2020-06-7助教一周小结(第14周)
    2020本科校招-从小白到拿到30k offer的学习经历
    2020-05-24助教一周小结(第13周)
    2020-05-17 助教一周小结(第十二周)
    2020-05-10 助教一周小结(第十一周)
    2020-05-04 助教一周小结(第十周)
    2020-04-26 助教一周小结(第九周)
    Ngnix搭建静态网页和安装wordpress
  • 原文地址:https://www.cnblogs.com/overrate-wsj/p/13264383.html
Copyright © 2011-2022 走看看