zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    ASP.NET MVC案例——————拦截器
    Windows Azure Virtual Network (10) 使用Azure Access Control List(ACL)设置客户端访问权限
    Windows Azure Storage (20) 使用Azure File实现共享文件夹
    Windows Azure HandBook (5) Azure混合云解决方案
    Windows Azure Service Bus (6) 中继(Relay On) 使用VS2013开发Service Bus Relay On
    Azure PowerShell (9) 使用PowerShell导出订阅下所有的Azure VM的Public IP和Private IP
    Windows Azure Service Bus (5) 主题(Topic) 使用VS2013开发Service Bus Topic
    Azure China (9) 在Azure China配置CDN服务
    Windows Azure Storage (19) 再谈Azure Block Blob和Page Blob
    Windows Azure HandBook (4) 分析Windows Azure如何处理Session
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7613217.html
Copyright © 2011-2022 走看看