zoukankan      html  css  js  c++  java
  • 【BZOJ 5000 OI树】

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 107  Solved: 64
    [
    Submit][Status][Discuss]

    Description

    几天之后小跳蚤即将结束自己在lydsy星球上的旅行。这时,lydsy人却发现他们的超空间传送装置的能量早在小跳

    蚤通过石板来到lydsy星球时就已经消耗光了。这时,小跳蚤了解到自己很有可能回不到跳蚤国了,于是掉下了伤

    心的眼泪……lydsy人见状决定无论如何也要送小跳蚤回地球,于是lydsy人的大祭司lavendir决定拜访lydsy星球

    的OI树,用咒语从OI树中取得能量。咒语中有K种字母,我们用前K个大写英文字母来表示它。OI树可以被认为是一

    个有着N个节点的带权有向图,所有节点的出度都是K,并且所有的出边都对应于一个咒语中的字母。仪式开始的时

    候有一个标记物放在OI树的1号节点上。之后,从咒语的第一个字母开始,每经过一个字母,标记物就沿着该字母

    对应的出边进入这条边的终点,并且得到相当于边权大小的能量值。当咒语处理完毕时,就可以得到这个过程中得

    到的所有能量了。现在由于lydsy人超群的计算能力,他们已经知道某咒语大概会获得多少能量,只是还想知道会

    获得的能量值对一个数M取模的结果。跳蚤国王通过小跳蚤留下的石板也了解到了小跳蚤现在的处境,所以他又找

    到了你,希望你帮助他计算出这个问题的答案。

    Input

    第一行是两个空格分隔的整数N和K。

    之后N行每行2*K个整数A_1,B_1,A_2,B_2,...,A_K,B_K,表示N个节点的K条出边。

    第i行表示第 i-1 个节点,这一行的A_S,B_S的值表示第S个大写字母对应的出边的终点为A_S,权值为B_S。

    下面一行有一个字符串,表示咒语。

    由于咒语的长度会非常长,将采用压缩方式给出,用[SA]表示连续S个字母A,S是一个正整数,A是单个字母。

    比如说,字符串[5A]BC[3A][3C]表示的咒语为AAAAABCAAACCC。

    之后一个正整数M,表示取模的底数。

    字符串长度≤120000,在一个压缩节[SA]中,S≤10^9。K≤26,N≤10000,M≤10^9,所有边的权值小于10^9

    Output

    一个整数,表示问题的答案。

    Sample Input

    4 2
    3 3 2 5
    1 7 3 2
    4 3 2 5
    2 10 3 2
    [3A]B[2A][2B]
    10000

    Sample Output

    38

    题解:

          ①突破口:题目中的咒语很长,但是有许多区间是一段相同的字母,即行走方向一定

          ②使用倍增数组预处理一直走同种字母2k步后积累的能量值

          ③询问的时候直接每一相同字母段进行倍增求值

    #include<stdio.h>
    #include<cstring>
    #define go(i,a,b) for(int i=a;i<=b;i++)
    #define ro(i,a,b) for(int i=a;i>=b;i--)
    const int N=10004;char s[120010];
    int n,K,M,u=1,ans=0,t,f[N][40][40],to[N][40][40];
    void Input_Data()
    {
    	scanf("%d%d",&n,&K);
        go(i,1,n)go(j,1,K){int a,b;scanf("%d%d",&a,&b);f[i][j][0]=b;to[i][j][0]=a;}
        scanf("%s%d",s+1,&M);
    }
    void Multiplication_Pre_Handle()
    {
    	go(k,1,31)go(i,1,n)go(j,1,K)
        /*Dis*/f[i][j][k]=(f[i][j][k-1]+f[to[i][j][k-1]][j][k-1])%M,
        /*Pos*/to[i][j][k]=to[to[i][j][k-1]][j][k-1];
    }
    void Calculate_Answer()
    {
    	int Len=strlen(s+1);
        go(i,1,Len)if(s[i]=='[')
        {/*Translate char to num for getting the len of the substring*/ 
            int d=0;i++;while(s[i]>='0'&&s[i]<='9')d=d*10+s[i]-'0',i++;t=s[i]-'A'+1;
         /*Use Multipilication-info to Calculate the answer*/       
            ro(j,31,0)if(d>=(1ll<<j))d-=(1<<j),ans=(ans+f[u][t][j])%M,u=to[u][t][j];i++;
        }else t=s[i]-'A'+1,ans=(ans+f[u][t][0])%M,u=to[u][t][0];
        printf("%d",ans);
    }
    int main()
    {
        Input_Data();
        
        Multiplication_Pre_Handle();
        
        Calculate_Answer();
        
        return 0;
    }//Paul_Guderian

    我不知道梦是什么颜色,也许它自有它的颜色,

    我不知道风要吹向哪里,也许它自有它的方向。————汪峰《迷鹿》

  • 相关阅读:
    唤醒控件曾经拥有的能力(重新继承是可以使用的.)
    为ASP.NET MVC应用程序创建更复杂的数据模型
    Akka入门实例
    最火的.NET开源项目(转)
    Roslyn 编译平台概述
    C#开发157
    ASP.NET MVC学习之控制器篇
    AngularJS中数据双向绑定(two-way data-binding)
    订单系统中并发问题和锁机制的探讨
    Visual Studio 编辑器
  • 原文地址:https://www.cnblogs.com/Damitu/p/7651645.html
Copyright © 2011-2022 走看看