The 2017 ACM-ICPC Asia Beijing Regional (賽後整理)

The 2017 ACM-ICPC Asia Beijing Regional (賽後整理)

PS: E,F是個大水題,但是因爲隊伍英語水平不高(菜是原罪),E題隊友40分鐘才A,我去讀F題,發現是個水題,20分鐘後又把F題A了,之後 J 題讀錯題意(successive 讀成“成功的”,導致理解錯題意,爆搜搞答案,當然是一直tle或wa到底)G題讀完發現是個sb題,bfs+線段多邊形規範相交就行,wa到底,比賽結束後發現我纔是sb,G題座標都沒轉換正確,線段多邊形規範相交還有一種情況沒判斷。H題讀完題意,發現不會。

比賽結束就A了2道,…好菜啊

不過這次的幾何G題和 區間dp J 題不錯。

E - Cats and Fish

思路:這道題用優先隊列或者set模擬一下即可,太水就鴿了吧(本來很早就要寫這題,不過沒時間…拖到現在也不想搞了)

F - Secret Poems

思路:斜着一遍把原字符串還原,然後蛇形填數形成新的grid即可。

水題

代碼:

#include<bits/stdc++.h>
#define  mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int N=1e2+10;
char g[N][N];
char a[N][N];
string s;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; ++i) scanf("%s",g[i]+1);
        s="";
        for(int i=1; i<=n; ++i)
        {
            if(i&1)//向上
            {
                for(int x=i,y=1; x>=1; x--,y++)
                    s+=g[x][y];
            }
            else
            {
                for(int x=1,y=i; y>=1; x++,y--)
                    s+=g[x][y];
            }
        }
        for(int i=2; i<=n; ++i)
        {
            if((n+i-1)&1)//向上
            {
                for(int x=n,y=i; y<=n; y++,x--)
                    s+=g[x][y];
            }
            else
            {
                for(int x=i,y=n; x<=n; x++,y--)
                    s+=g[x][y];
            }
        }
        mset(a,0);
        int k=0;
        a[1][1]=s[k++];
        int x=1,y=1;
        int mx=n*n;
        while(k < mx)
        {
            while(k < mx&&y < n&&a[x][y+1]==0)//向前走y++;
            {
                y++;
                a[x][y]=s[k++];
            }
            while(k<mx && x<n &&a[x+1][y]==0)//向下走  x++;
            {
                x++;
                a[x][y]=s[k++];
            }
            while(k<mx && y > 1&&a[x][y-1]==0)//向左走   y--;
            {
                y--;
                a[x][y]=s[k++];
            }
            while(k<mx &&x>1 && a[x-1][y] ==0)//向上走   x--
            {
                x--;
                a[x][y]=s[k++];
            }
        }
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=n; ++j)
                printf("%c",a[i][j]);
            puts("");
        }
    }
    return 0;
}

G - Liaoning Ship’s Voyage

題意:給出一個n*n的格子,和一個三角形,開始自己在左下角(0,0),現要去(n-1,n-1)座標。每次可以走周圍的8個方向,不能走’#’,每走一次的路線是直線,要求走的路線(線段)不能穿過三角形,但可以在三角形邊上走。問走的最小步數。n[1,20]n\in[1,20]

思路:bfs+線段多邊形規範相交吧,在輸入座標方面注意x軸是輸入的列,y軸是輸入的行,需要轉化下。判斷線段多邊形不規範相交,首先線段與多邊形的所有邊都不規範相交,其次兩個點都不在多邊形內,但可能出現兩個點在多邊形邊上,但中間的線段穿過多邊形,這時可以在多邊形上取幾百個點判斷下即可。

代碼:

#include<bits/stdc++.h>
#define  mset(a,b) memset(a,b,sizeof(a))
using namespace std;
double xx[10],yy[10];
double const eps=1e-8;
char gg[25][25],g[25][25];
int s[25][25];
int n;
int dir[8][2]= {0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
struct node
{
    int x,y,s;
    node() {}
    node(int x,int y,int s):x(x),y(y),s(s) {}
};
int sgn(double x)
{
    if(abs(x)<eps) return 0;
    if(x<0) return -1;
    else return 1;
}
double add(double a,double b)
{
   if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
    return a+b;
}
struct Point
{
    double x,y;
    Point() {}
    Point(double x,double y):x(x),y(y) {}
    Point operator -(Point p)
    {
        return Point(add(x,-p.x),add(y,-p.y));
    }
    Point operator +(Point p)
    {
        return Point(add(x,p.x),add(y,p.y));
    }
    double operator ^(Point p)
    {
        return add(x*p.y,-y*p.x);
    }
    Point operator *(double d)
    {
        return Point(x*d,y*d);
    }
    double operator *(Point p)
    {
        return add(x*p.x,y*p.y);
    }
} avg[3];
struct Line
{
    Point s,e;
    Line() {}
    Line(Point s,Point e):s(s),e(e) {}
} line[10];
int getDirPPP(Point p,Point p1,Point p2)
{
    return sgn((p1-p)^(p2-p));
}
bool onSge(Line l,Point q)
{
    return ((l.s-q)^(l.e-q))==0&&((l.s-q)*(l.e-q)) <=0;
}
bool isInterSS(Line la,Line lb)//判斷規範相交
{
    int d1=getDirPPP(lb.s,lb.e,la.s);
    int d2=getDirPPP(lb.s,lb.e,la.e);
    int d3=getDirPPP(la.s,la.e,lb.s);
    int d4=getDirPPP(la.s,la.e,lb.e);
    if(d1*d2<0&&d3*d4<0)
        return true;
    return  false;
}
bool notinari(Point a)//點在三角形內返回flase//邊上返回true
{
    for(int i=0; i<3; ++i)
        if(getDirPPP(a,avg[i],avg[(i+1)%3])==0) return true;
    if(getDirPPP(a,avg[0],avg[1]) < 0&& getDirPPP(a,avg[1],avg[2])<0 && getDirPPP(a,avg[2],avg[0])<0) return false;
    if(getDirPPP(a,avg[0],avg[1]) > 0&& getDirPPP(a,avg[1],avg[2])>0 && getDirPPP(a,avg[2],avg[0])>0) return false;
    return true;

}
bool judge(Line a)
{
    for(int i=0; i<3; ++i)
        if(isInterSS(a,line[i]))
            return false;
    double d=0.01,s=1;
    for(int i=0; i<100; ++i)
    {
        Point t=a.e+(a.s-a.e)*s;
        if(!notinari(t)) return false;
        s-=d;
    }
    if(notinari(a.s)&&notinari(a.e))
        return true;
    else
        return false;
}
int work()//下標從0開始
{
    mset(s,-1);
    s[0][0]=0;
    queue<node> Q;
    Q.push(node(0,0,0));
    while(!Q.empty())
    {
        node o=Q.front();
        Q.pop();
        for(int i=0; i<8; ++i)
        {
            int nx=o.x+dir[i][0];
            int ny=o.y+dir[i][1];

            if(nx>=0&&nx<n&&ny>=0&&ny<n&&g[nx][ny]=='.'&&s[nx][ny]==-1)
            {
                if(judge(Line(Point(1.0*nx,1.0*ny),Point(1.0*o.x,1.0*o.y))))
                {
//                    printf("--nx:%d,ny:%d\n",nx,ny);
                    Q.push(node(nx,ny,o.s+1));
                    s[nx][ny]=o.s+1;
                }
            }
        }
    }
    return s[n-1][n-1];
}
int main()
{

    while(~scanf("%d",&n))
    {
        for(int i=0; i<3; ++i)
        {
            scanf("%lf%lf",&xx[i],&yy[i]);
            avg[i]=Point(xx[i],yy[i]);
        }

        int top=0;
        for(int i=0; i<3; ++i)
            for(int j=i+1; j<3; ++j) //3
                line[top++]=Line(Point(xx[i],yy[i]),Point(xx[j],yy[j]));
        for(int i=n-1; i >=0; --i)
            scanf("%s",gg[i]);
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
                g[i][j]=gg[j][i];
        cout<<work()<<endl;
    }
    return 0;
}

H - Puzzle Game

題意:給出一個n*m的矩形和一個整數p,可以選擇在矩形中選擇一個數將之變成p,要求最後的最大子矩陣和最小。n,m[1,150],ai,j,p[1000,1000]n,m\in[1,150],a_{i,j},p\in[-1000,1000]

思路:不會

J - Pangu and Stones

題意:給出n個石子和石子的重量,每次可以選擇L到R個石子合併成一個,花費爲合併的石子的重量,求合併成一堆的最小花費,不能合成一堆輸出0。n[2,100],2lrnn\in[2,100],2\le l\le r\le n​

思路

這題感覺很有意思,我們用dp[i][j][k]dp[i][j][k]表示狀態,但是這個狀態的含義有些豐富(

k=1k=1​時,dp[i][j][1]dp[i][j][1]​表示 ii​jj​ 的石子合併成一堆所需的最小花費。

k>1k>1​時,dp[i][j][k]dp[i][j][k]​表示 ii​jj​ 的石子劃分成 kk​堆的最小花費,注意這裏的劃分是還沒有合併,只是劃分。

轉移方程:

dp[i][j][1]=min(dp[i][j][1],dp[i][j][k]+sum[i][j]),k[l,r]dp[i][j][1]=min(dp[i][j][1],dp[i][j][k]+sum[i][j]),k\in[l,r]​。注意這裏的sum[i][j]sum[i][j]​表示 ii​jj​ 的總重量,這個狀態轉移表示的是一次合併操作,

k>1k>1​時,dp[i][j][k]=min(dp[i][j][k],dp[i][c][1]+dp[c+1][j][k1]),c[i,jk+1]dp[i][j][k]=min(dp[i][j][k],dp[i][c][1]+dp[c+1][j][k-1]),c\in[i,j-k+1]​ ,這裏表示的是劃分操作。

代碼

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=105;
const int inf=0x3f3f3f3f;
int a[N],sum[N];
int dp[N][N][N];
int main()
{
    int n,L,R;
    while(~scanf("%d%d%d",&n,&L,&R))
    {
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=n; ++j)
                for(int k=1; k<=R; ++k) dp[i][j][k]=inf;
        for(int i=1; i<=n; ++i) sum[i]=sum[i-1]+a[i];
        for(int i=1; i<=n; ++i) dp[i][i][1]=0;
        for(int ls=2; ls<=n; ++ls)
        {
            for(int l=1; l+ls-1 <= n; ++l)
            {
                int r=l+ls-1;
                //先處理k\in[2,R]的情況
                for(int k=2; k<=R; ++k) //dp    r-c>=k-1  c<=r-k+1
                {
                    for(int c=l; c<=r-k+1; ++c) //dp[l][c][1] +dp[c+1][r][k-1]
                        dp[l][r][k]=min(dp[l][r][k],dp[l][c][1]+dp[c+1][r][k-1]);
                }
                //處理k=1的情況
                for(int k=L; k<=R; ++k)
                    dp[l][r][1]=min(dp[l][r][1],dp[l][r][k]+sum[r]-sum[l-1]);
            }
        }
        if(dp[1][n][1]==inf)
            printf("0\n");
        else
            printf("%d\n",dp[1][n][1]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章