1. 程式人生 > >【BZOJ 5000 OI樹】

【BZOJ 5000 OI樹】

[0 bar 有一個 for tip 突破口 所有 http tool

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

我不知道夢是什麽顏色,也許它自有它的顏色,

我不知道風要吹向哪裏,也許它自有它的方向。————汪峰《迷鹿》

【BZOJ 5000 OI樹】