2019-8-12 考试总结

A. 引子 

大模拟。

先标记水箱的位置,然后顺着每条水管走,最后$dfs$就可以了。

丑陋的代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#define int long long
#define Maxn 1050
#define Reg register
#define _max(x,y) ((x)>(y)?(x):(y))
using namespace std;
int n,m,cnt,tot,num[Maxn][Maxn];
int Lx[Maxn*Maxn],Rx[Maxn*Maxn],Ly[Maxn*Maxn],Ry[Maxn*Maxn],stack[Maxn*Maxn];
char s[Maxn][Maxn];
vector<vector<int> > son(Maxn*Maxn);
int find(int x,int y,int k)
{
    if(x<1||x>n||y<1||y>m) return -1;
    if(num[x][y]) return num[x][y];
    else if(s[x][y]=='|')
    {
        s[x][y]='.';
        if(s[x+1][y]=='|'||s[x+1][y]=='+'||(num[x+1][y]&&num[x+1][y]!=k)) return find(x+1,y,k);
        else if(s[x-1][y]=='|'||s[x-1][y]=='+'||(num[x-1][y]&&num[x-1][y]!=k)) return find(x-1,y,k);
    }
    else if(s[x][y]=='-')
    {
        s[x][y]='.';
        if(s[x][y+1]=='-'||s[x][y+1]=='+'||(num[x][y+1]&&num[x][y+1]!=k)) return find(x,y+1,k);
        else if(s[x][y-1]=='-'||s[x][y-1]=='+'||(num[x][y-1]&&num[x][y-1]!=k)) return find(x,y-1,k);
    }
    else if(s[x][y]=='+')
    {
        s[x][y]='.';
        if(s[x+1][y]=='|'||s[x+1][y]=='+'||(num[x+1][y]&&num[x+1][y]!=k)) return find(x+1,y,k);
        else if(s[x-1][y]=='|'||s[x-1][y]=='+'||(num[x-1][y]&&num[x-1][y]!=k)) return find(x-1,y,k);
        else if(s[x][y+1]=='-'||s[x][y+1]=='+'||(num[x][y+1]&&num[x][y+1]!=k)) return find(x,y+1,k);
        else if(s[x][y-1]=='-'||s[x][y-1]=='+'||(num[x][y-1]&&num[x][y-1]!=k)) return find(x,y-1,k);
    }
    return -1;
}
void dfs(int x)
{
    for(Reg int i=0;i<son[x].size();++i) dfs(son[x][i]);
    stack[++stack[0]]=x;
    return;
}
signed main()
{
    scanf("%lld%lld",&n,&m);
    for(Reg int i=0;i<=n+1;++i)
        for(Reg int j=0;j<=m+1;++j) s[i][j]='.';
    for(Reg int i=1;i<=n;++i) scanf("%s",s[i]+1);
    for(Reg int i=1;i<=n;++i)
    {
        for(Reg int j=1;j<=m;++j)
        {
            if(s[i][j]=='.') continue;
            else if(s[i][j]=='+')
            {
                int lnow=j,rnow=j+1,unow=i,dnow=i+1,ok=1;
                while(rnow<m&&s[i][rnow]=='-') ++rnow;
                while(dnow<n&&s[dnow][j]=='|') ++dnow;
                if(rnow>m||dnow>n) continue;
                for(Reg int k=lnow+1;k<=rnow-1;++k) if(s[dnow][k]!='-') {ok=0; break;}
                for(Reg int k=unow+1;k<=dnow-1;++k) if(s[k][rnow]!='|') {ok=0; break;}
                if(!ok) continue;
                if(s[i][rnow]=='+'&&s[dnow][j]=='+'&&s[dnow][rnow]=='+')
                {
                    int po=0;
                    for(Reg int k=unow;k<=dnow;++k)
                    {
                        for(Reg int p=lnow;p<=rnow;++p)
                        {
                            if(s[k][p]>='0'&&s[k][p]<='9')
                                po=po*10+s[k][p]-'0';
                            s[k][p]='.';
                        }
                    }
                    if(!po) continue;
                    for(Reg int k=unow;k<=dnow;++k)
                        for(Reg int p=lnow;p<=rnow;++p) num[k][p]=po;
                    cnt=_max(cnt,po);
                    Lx[po]=unow,Rx[po]=dnow,Ly[po]=lnow,Ry[po]=rnow;
                }
            }
        }
    }
    for(Reg int i=1;i<=cnt;++i)
    {
        for(Reg int j=Rx[i];j>=Lx[i];--j)
        {
            if(s[j][Ly[i]-1]=='-')
            {
                int p=find(j,Ly[i]-1,i);
                if(p!=-1) son[i].push_back(p);
            }
            if(s[j][Ry[i]+1]=='-')
            {
                int p=find(j,Ry[i]+1,i);
                if(p!=-1) son[i].push_back(p);
            }
        }
    }
    dfs(1);
    for(Reg int i=1;i<=stack[0];++i) printf("%lld\n",stack[i]);
    return 0;
}
View Code

 

B. 可爱精灵宝贝

乍一看这个题像一个很简单的$dp$,

如果精灵不消失的话,那么就很简单了。

但是精灵被抓住后会消失,这就有点难了。

正解:

用$dp[t][l][r][0/1]$表示状态,在第$t$秒左侧拓展到$l$,右侧拓展到$r$,现在在左端点$(0)/$在右端点$(1)$的最大收益。

为什么可以这样。

显然,要抓到一个精灵必须经过这个精灵到原点$k$之间的点,

而如果这个点已经走过,那么再走肯定不会有收益。

只要先把所有的精灵按照位置排序,然后枚举时间、左右端点就可以了。

下面是转移:

好吧很麻烦,看代码。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define Maxn 2050
#define Reg register
#define INF 0x7fffff
#define _max(x,y) ((x)>(y)?(x):(y))
#define _abs(x) ((x)<0?(-1*(x)):(x))
using namespace std;
int n,k,m,mxx=0,ans=0,tot=0,mid,dp[Maxn][150][150][2];
struct Node {int a,b,t;} Q[Maxn];
bool comp(Node a,Node b) {return a.a<b.a;}
int main()
{
    scanf("%d%d%d",&n,&k,&m);
    Q[++tot].a=k,Q[tot].b=0,Q[tot].t=0;
    for(Reg int i=1,a,b,t;i<=m;++i)
    {
        scanf("%d%d%d",&a,&b,&t);
        if(a==k) Q[1].b+=b;
        else
        {
            Q[++tot].a=a,Q[tot].b=b,Q[tot].t=t;
            mxx=_max(mxx,Q[tot].t);
        }
    }
    sort(Q+1,Q+tot+1,comp);
    for(Reg int i=1;i<=tot;++i) if(Q[i].a==k) mid=i;
    for(Reg int i=1;i<=mxx;++i)
        for(Reg int j=mid;j>=1;--j)
            for(Reg int p=mid;p<=tot;++p)
                dp[i][j][p][0]=dp[i][j][p][1]=-INF;
    dp[1][mid][mid][0]=dp[1][mid][mid][1]=Q[mid].b;
    for(Reg int i=1;i<=mxx;++i)
    {
        for(Reg int j=mid;j>=1;--j)
        {
            for(Reg int p=mid,sum;p<=tot;++p)
            {
                if(p+1<=tot&&i+Q[p+1].a-Q[j].a<=mxx)
                {
                    sum=dp[i][j][p][0];
                    if(Q[p+1].t>=i+Q[p+1].a-Q[j].a) sum+=Q[p+1].b;
                    dp[i+Q[p+1].a-Q[j].a][j][p+1][1]=_max(dp[i+Q[p+1].a-Q[j].a][j][p+1][1],sum);
                }
                if(j-1>=1&&i+Q[j].a-Q[j-1].a<=mxx)
                {
                    sum=dp[i][j][p][0];
                    if(Q[j-1].t>=i+Q[j].a-Q[j-1].a) sum+=Q[j-1].b;
                    dp[i+Q[j].a-Q[j-1].a][j-1][p][0]=_max(dp[i+Q[j].a-Q[j-1].a][j-1][p][0],sum);
                }
                if(j-1>=1&&i+Q[p].a-Q[j-1].a<=mxx)
                {
                    sum=dp[i][j][p][1];
                    if(Q[j-1].t>=i+Q[p].a-Q[j-1].a) sum+=Q[j-1].b;
                    dp[i+Q[p].a-Q[j-1].a][j-1][p][0]=_max(dp[i+Q[p].a-Q[j-1].a][j-1][p][0],sum);
                }
                if(p+1<=tot&&i+Q[p+1].a-Q[p].a<=mxx)
                {
                    sum=dp[i][j][p][1];
                    if(Q[p+1].t>=i+Q[p+1].a-Q[p].a) sum+=Q[p+1].b;
                    dp[i+Q[p+1].a-Q[p].a][j][p+1][1]=_max(dp[i+Q[p+1].a-Q[p].a][j][p+1][1],sum);
                }
                ans=_max(ans,_max(dp[i][j][p][0],dp[i][j][p][1]));
            }
        }
    }
    printf("%d",ans);
    return 0;
}
View Code

 

C. 相互再归的鹅妈妈 

 

总结:

$T1$是个大模拟,

数组开小$+$判水箱判错让我丢了$20$分,拿到$80$,

$T1$大概码了不到一个小时,然后去看$T2$。

$T2$看起来很简单,题目很好懂,

一开始很自然地想到二维$dp$,但很快被$Hack$掉。

观察题目性质,然后这个正解便很好想。

$T2$码了一个多小时,然后又调了很长时间。

最后剩下$T3$,好吧,容斥?组合数?一堆数学的东西。

看起来很像按位转移的$dp$,好像没多少时间了。

还是输出样例吧。。。

总的来说心态很好(尤其是看到$T1$是个大模拟),

$T2$能好好想了。

时间分配,$T2$时间有点长,总的来说应该还行。

好像给$T3$时间多了也拿不了多少分。。。

不能想当然,很容易拿到$WA$。

最后$80+100+10=190$

没什么水平。。。

posted @ 2019-08-12 15:07  Milk_Feng  阅读(132)  评论(0编辑  收藏  举报