2019ICPC南京现场赛 C-digit path 拓扑dp

说来惭愧,A题卡了4个小时我都不信,都最后铜也没拿上。。

 

题意:

找长度大于等于4的 严格递增差1 的 能在扩增的 路线有多少条。

题目思路:

严格递增差一,很容易想到,有向无环图(DAG)

我们在DAG上进行拓扑DP就可以乐,因为拓扑满足无后效性

所以,我们直接找出状态转移方程:

            dp[e][2]=(dp[e][2]+dp[u][1])%mod;
            dp[e][3]=(dp[e][3]+dp[u][2])%mod;
            dp[e][4]=(dp[e][4]+dp[u][3]+dp[u][4])%mod;

然后 入度为0的点 dp[i][1]=1;

上述转移方程的意思是:到达该点长度为3的+等于前一个点到达长度为2的数量,特别的,到达该点大于等于4的+等于到达前一个长度为3的与到达前一个点长度大于等于4的。

然后就过了...

说来很伤心..明年去南京复仇叭...加油!

不负领导,不负队友!

AC:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=1e6+5;
using namespace std;
ll n,m;
int mp[1005][1005];
ll dp[maxn][6];
int pos[1005][1005];
int in[maxn],out[maxn];
struct node{
    int e,next;
}edge[maxn*4];
int head[maxn*4];
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
ll cnt=0;
void addedge(int u,int v)
{
    edge[cnt]=node{v,head[u]};
    head[u]=cnt++;
}
void Torder()
{
    queue<int>q;
    for(int i=1;i<=n*m;i++)
    {
        if(!in[i])
        {
            q.push(i);
            dp[i][1]=1;
        }
    }
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=head[u];~i;i=edge[i].next)
        {
            int e=edge[i].e;
            in[e]--;
            dp[e][2]=(dp[e][2]+dp[u][1])%mod;
            dp[e][3]=(dp[e][3]+dp[u][2])%mod;
            dp[e][4]=(dp[e][4]+dp[u][3]+dp[u][4])%mod;
            if(!in[e]) q.push(e);
        }
    }
}
int main()
{
    int cot=0;
    memset(dp,0,sizeof(dp));
    memset(head,-1,sizeof(head));
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
        for(int k=1;k<=m;k++)
        {
            scanf("%lld",&mp[i][k]);
            pos[i][k]=++cot;
        }
    for(int i=1;i<=n;i++)
    {
        for(int k=1;k<=m;k++)
        {
            for(int j=0;j<4;j++)
            {
                int mx=i+dx[j],my=k+dy[j];
                if(mp[i][k]+1==mp[mx][my]&&mx>=1&&my>=1&&mx<=n&&my<=m)
                {
                    addedge(pos[i][k],pos[mx][my]);
                    in[pos[mx][my]]++;
                    out[pos[i][k]]++;
                }
            }
        }
    }
    Torder();
    ll res=0;
    for(int i=1;i<=n*m;i++)
    {
        if(!out[i])
        {
            res+=dp[i][4];
            res%=mod;
        }
    }
    printf("%lld\n",res);
    return 0;
}

/**

**/

 

全部评论

相关推荐

1.&nbsp;多做一劳永逸的事情。很多事情一次学会基本可以大学四年都不再为这类事情发愁。小的比如学会markdown,记笔记就变得方便快捷;大的比如自己经常要发布上线服务,就花几天搭建一个集群。2.&nbsp;时刻具备3-7天掌握一项技能的心理准备。无论是学科竞赛、期末考试,还是准备实习、秋招,很多时候当你需要快速运用某项技能做事的时候,不会有那么多时间给你准备,这时候就需要速成。3.&nbsp;加入/组建一个技术团体,社团/面试群/社群/技术博主的圈子,并且养成水群习惯。只有你参与并融入你正在追求的事业的氛围里,你才能保持动力去做一件事。推荐一个博主【程序员牛肉】的圈子:https://pd.qq.com/s/daelsgft54.&nbsp;尽早明确自己距离目标还差什么。很多人学习的非常努力,但是方向不明确。最简单的例子,很多我帮忙找实习秋招的朋友,简历都过不了,却花大把时间在背八股上。面试的过程是阶段性的,要考虑的先是有面试机会、再是怎么面试。5.&nbsp;思维不要被约束。后端语言java、c++可以,golang也可以;项目苍穹外卖、黑马点评可以,github上的高star项目也可以;数据库用mysql、redis可以,用postgresql也可以;项目里的ai模块用rag、mcp可以,最简单的function&nbsp;call也可以。帮很多人看简历问题的时候,很多东西都是硬写上去的,项目是自己的,不是非要和网上大流一致才是好项目。
想进开水团喝开水:杭电也是双非是吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务