zoukankan      html  css  js  c++  java
  • 牛客网NOIP赛前集训营-提高组(第六场)A-最长路

    题目描述

    有一张 n 个点 m 条边的有向图,每条边上都带有一个字符,字符用一个数字表示。

    求以每个点为起点的最长路,输出走过的边的字符构成的字符串的字典序最小的方案。

    为了方便,你需要这样输出方案:

    如果最长路无限长,则输出Infinity

    否则假设方案走过的边的字符依次为 w1,w2,..wk ,输出 img

    输入描述:

    第一行两个整数 n,m ,表示有向图的结点个数和边数。

    接下来 m 行,每行三个整数 x,y,w ,表示有一条从 x 连向 y 的边,上面有字符 w 。

    输出描述:

    对于每个询问,输出一行,表示答案。

    示例1

    输入

    5 6
    1 2 0
    2 1 0
    3 4 2
    4 5 3
    4 5 1
    3 5 1
    

    输出

    Infinity
    Infinity
    899
    29
    0
    

    说明

    img

    以第 1 个点和第 2 个点为起点的最长路都是无限长,输出Infinity
    以第 3 个点为起点的最长路为 2 条边,有两种方案,走过的边的字符构成的字符串分别为
    {2,3} 和 { 2,1} ,其中 { 2,1} 的字典序更小,所以输出(2 	imes 29 +1 	imes 29^2) mod 998244353=899
    以第 4 个点为起点的最长路为 1 条边,有两种方案,走过的边的字符构成的字符串分别为
    {3} 和 { 1} ,其中 { 1} 的字典序更小,所以输出 (1 	imes 29) mod 998244353=29
    以第 5 个点为起点的最长路为 0 条边,注意此时应输出 0 。

    备注:

    全部的输入数据满足:

    • (1 ≤ n ≤ 1000000)
    • (1 ≤ m ≤ 1000000)
    • (0 ≤ ext{字符} ≤ 10^9)

    各个测试点的性质如下:(若为空,则表示没有特殊性质)

    img

    Solution

    显然如果一个能连到一个环那就是Infinity

    那么去掉这些点以后就是个DAG,显然跑DP。其中前80分都可以直接暴力DP得来。

    唯一的问题是如何快速判断两个决策的优劣。

    如果是两个给你的字符串保证一样长,让你比较字典序,可以最多做(O(n))的预处理,要求比较(O(log n))做完。那么显然做一个哈希,然后二分它们开始不一样的位置或者倍增找。找到以后比较下一位。

    那么在这个题里面,显然不能二分,因为没有明显的序列。那么考虑倍增,每个点维护其最优决策里(s[i][j])表示(i)这个点往后(2^j)位的点。哈希值也很好维护的,所以就做完了。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define lowbit(x) ((x)&(-(x)))
    #define REP(i,a,n) for(register int i=(a);i<=(n);++i)
    #define PER(i,a,n) for(register int i=(a);i>=(n);--i)
    #define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
    template<typename A>inline void read(A&a){a=0;char c=0;int f=1;while(c<'0'||c>'9')(c=getchar())=='-'?f=-1:0;while(c>='0'&&c<='9')a=(a<<3)+(a<<1)+c-'0',c=getchar();f==-1?a=-a:0;}
    char buf[30];template<typename A>inline void write(A a){if(a<0)putchar('-'),a=-a;int top=0;if(!a)buf[top=1]='0';while(a)buf[++top]=a%10+'0',a/=10;while(top)putchar(buf[top--]);}
    typedef long long ll;typedef unsigned long long ull;
    template<typename A,typename B>inline bool SMAX(A&x,const B&y){return y>x?x=y,1:0;}
    template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}
      
    const int N=1000000+7,MOD=998244353,base=3007,LOG=21;
    int n,m,x,y,z;
    struct Edge{int to,ne,w;}g[N];int head[N],tot;
    inline void Addedge(int x,int y,int z){g[++tot].to=y;g[tot].w=z;g[tot].ne=head[x];head[x]=tot;}
      
    int vis[N],hkk[N];int s[N][LOG];ull bin[N];
    struct Node{
        int c,hash;ull h2;
        inline bool Check(){return ~c;}
    }dp[N];
    inline bool cmp(int a,int b){
        for(register int i=LOG-1;i>=0;--i)
            if(s[a][i]&&s[b][i]&&dp[a].h2-dp[s[a][i]].h2*bin[1<<i]==dp[b].h2-dp[s[b][i]].h2*bin[1<<i])a=s[a][i],b=s[b][i];
        return dp[a].h2-dp[s[a][0]].h2*base<dp[b].h2-dp[s[b][0]].h2*base;
    }
    inline Node DFS(int x){
        if(hkk[x])return Node{-1,0,0};if(vis[x])return dp[x];
        Node &ans=dp[x]={0,0,0};vis[x]=hkk[x]=1;int pre=-1,ch=1e9;
        for(register int i=head[x];i;i=g[i].ne){
            int y=g[i].to;Node &f=dp[0]=DFS(y);
            if(!f.Check())return ans={-1,0,0};
            else f.c++,f.hash=((ll)f.hash*29%MOD+(ll)g[i].w*29%MOD)%MOD,!~pre||f.c>ans.c||(f.c==ans.c&&(g[i].w<ch||(g[i].w==ch&&cmp(y,pre))))?ans=f,pre=g[i].to,ch=g[i].w:0;
        }hkk[x]=0;
        ans.h2=ans.h2*base+ch;s[x][0]=pre;if(~pre)for(register int i=1;i<LOG;++i)s[x][i]=s[s[x][i-1]][i-1];
        return ans;
    }
    inline void Work(){
        bin[0]=1;for(register int i=1;i<=n;++i)bin[i]=bin[i-1]*base;
        for(register int i=1;i<=n;++i){
            DFS(i);
            if(!dp[i].Check())puts("Infinity");
            else write(dp[i].hash),putchar('
    ');
        }
    }
    
    int main(){
        read(n),read(m);
        for(register int i=1;i<=m;++i)read(x),read(y),read(z),Addedge(x,y,z);
    	Work();
    }
    
  • 相关阅读:
    用vue前后端分离项目开发记录
    使用 JavaScript 将网站后台的数据变化实时更新到前端
    怎么使用 JavaScript 将网站后台的数据变化实时更新到前端
    修改el-table滚动条样式
    修改浏览器滚动条样式
    查找和替换img src
    cookie添加删除修改
    如何处理CSS3属性前缀
    PostCSS深入学习: PostCSS和Sass、Stylus或LESS一起使用
    在 CSS 预编译器之后:PostCSS
  • 原文地址:https://www.cnblogs.com/hankeke/p/nowcoder-noiptg6-A.html
Copyright © 2011-2022 走看看