2019 ICPC Malaysia National 题解

Posted overrate-wsj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

 

 

 

 

 

 

 

以上是关于2019 ICPC Malaysia National 题解的主要内容,如果未能解决你的问题,请参考以下文章

2019 ICPC Malaysia National H题

2019 ICPC Malaysia National F(状态压缩)

ICPC 2018 Malaysia-EXPLORACE

ICPC 2019宁夏网络赛

2019 ICPC 南昌网络赛

ICPC2019南昌区域赛