• bzoj 5000: OI树


    Description
    几天之后小跳蚤即将结束自己在lydsy星球上的旅行。这时,lydsy人却发现他们的超空间传送装置的能量早在小跳
    蚤通过石板来到lydsy星球时就已经消耗光了。这时,小跳蚤了解到自己很有可能回不到跳蚤国了,于是掉下了伤
    心的眼泪……lydsy人见状决定无论如何也要送小跳蚤回地球,于是lydsy人的大祭司lavendir决定拜访lydsy星球
    的OI树,用咒语从OI树中取得能量。咒语中有K种字母,我们用前K个大写英文字母来表示它。OI树可以被认为是一
    个有着N个节点的带权有向图,所有节点的出度都是K,并且所有的出边都对应于一个咒语中的字母。仪式开始的时
    候有一个标记物放在OI树的1号节点上。之后,从咒语的第一个字母开始,每经过一个字母,标记物就沿着该字母
    对应的出边进入这条边的终点,并且得到相当于边权大小的能量值。当咒语处理完毕时,就可以得到这个过程中得
    到的所有能量了。现在由于lydsy人超群的计算能力,他们已经知道某咒语大概会获得多少能量,只是还想知道会
    获得的能量值对一个数M取模的结果。跳蚤国王通过小跳蚤留下的石板也了解到了小跳蚤现在的处境,所以他又找
    到了你,希望你帮助他计算出这个问题的答案。

    解题报告:
    用时:20min,3WA
    这题比较良心,看到数据范围可以想到可以倍增或矩阵优化,这题显然是倍增,我们可以处理出每一个字母的倍增数组,即(f[k][i][j]) 表示从i节点开始,沿(k)这个字母对应的边,走(2^j)步的父节点,同理也可以处理出权值和,然后分段跑倍增即可

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #define RG register
    #define il inline
    #define iter iterator
    #define Max(a,b) ((a)>(b)?(a):(b))
    #define Min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int N=10005;
    int fa[28][N][35],n,m,v[28][N][35];char s[120005];
    struct node{int x,t;}q[120005];
    void work()
    {
       scanf("%d%d",&n,&m);
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
             scanf("%d%d",&fa[j][i][0],&v[j][i][0]);
       scanf("%s",s+1);
       int l=strlen(s+1),cnt=0,p=0;
       for(int i=1;i<=l;i++){
          if(s[i]=='['){
             cnt++;p=i+1;
             while(p<=l && s[p]>='0' && s[p]<='9')q[cnt].x=q[cnt].x*10+s[p]-48,p++;
             q[cnt].t=s[p]-'A'+1;
             i=p+1;
          }
          else q[++cnt].x=1,q[cnt].t=s[i]-'A'+1;
       }
       int mod;cin>>mod;
       for(int i=1;i<=n;i++)
          for(int j=1;j<=m;j++)
             if(v[j][i][0]>=mod)v[j][i][0]%=mod;
       for(int k=1;k<=m;k++)
          for(int j=1;j<=30;j++)
             for(int i=1;i<=n;i++)
                fa[k][i][j]=fa[k][fa[k][i][j-1]][j-1],
                   v[k][i][j]=v[k][fa[k][i][j-1]][j-1]+v[k][i][j-1],v[k][i][j]%=mod;
       int ans=0,x=1,res,k;
       for(int i=1;i<=cnt;i++){
          res=q[i].x;k=q[i].t;
          for(int j=30;j>=0;j--)
             if(res&(1<<j)){
                ans+=v[k][x][j];x=fa[k][x][j];
                if(ans>=mod)ans-=mod;
             }
       }
       printf("%d
    ",ans);
    }
     
    int main()
    {
        work();
        return 0;
    }
    
  • 相关阅读:
    七 使用list和tuple
    python 操作RabbitMQ
    python 操作Memcached
    python 操作SQLAlchemy
    Scrapy 分布式爬虫
    Django 测试驱动开发
    Flask 页面缓存逻辑,jinja2 过滤器,测试器
    Flask Markup 上下文,request
    Flask 学习 十六 部署
    Flask 学习 十五 性能
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7613217.html
Copyright © 2020-2023  润新知