while my guitar gently weeps(while)


while my guitar gently weeps(while)

題目背景

(不保證題目背景與題意無關)

吉他自那以后就被擱置在小屋里。

他靜靜想着,以后要去山坡的雲霧繚繞,要去河邊的月光似水,哪怕是巷陌街頭的熙熙攘攘。最好能登上閃光燈下的舞台,讓歡呼環抱在身邊,讓掌聲縈繞在心畔。“鈿頭銀篦擊節碎,血色羅裙翻酒污”自是每個主人的夢想,自也是每把吉他輕輕許下的願望。

漸漸地,小屋里爬滿了灰塵,樹蔭鏤過的陽光有時溜進來,隱約着翻飛的雜塵。

吉他只細細數着幾次雞鳴,又幾番夕落,心也一天天老了下去。

直到某一天,第一根琴弦輕輕掙斷,那是吉他的嗚噎。

這根琴弦——猶記主人第一天把弄琴弦就是從這里開始的,好奇地不停彈響這第一種天籟。每每秋日午后,坐在窗台上,陽光像現在一樣明亮,楊樹的葉像現在一般沙響,幾曲情歌,幾支小調,落下的秋葉都記得這些事。又何堪回首幾度春秋,多少番喜怒哀樂,多少輪陰晴圓缺,不論什么都可以在吉他里消遣。

——斷了。

直到某一天,第二根琴弦輕輕掙斷,那是吉他的抽泣。

這根琴弦——猶記主人第一次撥弄心弦就是從這里開始的,坐在河畔,月影靜靜地浮在水面上,風吹過的水面潺潺作響,仿佛流進心房,就像他和她心跳的聲音一樣。只記得浪漫的曲聲悠揚,飄出厚厚的蘆葦盪,飄進甜甜的夢鄉,是夜夜囈語,是道阻且長。

——斷了。

直到某一天,第三根琴弦輕輕掙斷,那是吉他的哀鳴。

這根琴弦——猶記主人第一次投趣心閑就是從這里開始的,常是暮春雨后,亦或月圓時節,撥一曲舒緩小調,執筆填一首雅趣小詞,揮筆描摹一幅山水畫卷,或是傾心栽培一株厭陽的小花……不知什么時候眼里的柔情變淡了,就連眼淚也不似以往咸甜;不知什么時候心性變得笨拙了,連琴弦上飛翻的手指都似乎沾染了思慮與焦灼。可終究我們都在,還同以往一樣親近,一樣喜歡風吹過的聲響。

——斷了。

不知過了多久,主人的面龐才從小屋的門縫里鑽進來——那是多么疲憊的一張臉啊,可淡淡的目光里分明看得出解脫,或許還有成長里的自得,還有重逢后的欣喜。

題目描述

又是秋末冬初,主人再次撥響了吉他殘存的琴弦。主人每次從一側彈入一個音符,每次在一根琴弦處可以發生反彈,當然也可以穿過這根琴弦。當音符第一次穿過一根邊界琴弦時開始彈響,最后一次穿出邊界琴弦時為曲終。

定義函數 \(f(i)\) 表示音符在琴中反彈 \(i-2\) 次的方案數,並定義 \(f(1)=1\)

定義第零天的 \(f\) 值為 \(n\),以后每一天都反彈上一天的 \(f\) 值的次,以此類推,持續 \(k\) 天。

問第 \(k\) 天的 \(f\) 值模 \(p\)

輸入格式

一行三個整數 \(n,k,p\)

輸出格式

一行一個整數,表示答案。

樣例

樣例輸入 1

7 2 1000003

樣例輸出 1

233

樣例輸入 2

7 5 1000003

樣例輸出 2

697759

數據范圍與提示

Subtask編號 分值 \(n\le\) \(k\le\) 特殊性質
\(\texttt{1}\) \(\texttt{1}\) \(10^{10^7}\) \(10^{18}\) \(p=1\)
\(\texttt{2}\) \(\texttt{5}\) \(10^{10^7}\) \(0\) \(/\)
\(\texttt{3}\) \(\texttt{9}\) \(10^7\) \(1\) \(/\)
\(\texttt{4}\) \(\texttt{15}\) \(6\) \(5\) \(/\)
\(\texttt{5}\) \(\texttt{18}\) \(10^{10^7}\) \(10^7\) \(/\)
\(\texttt{6}\) \(\texttt{2}\) \(1\) \(10^{18}\) \(/\)
\(\texttt{7}\) \(\texttt{20}\) \(10^{18}\) \(10^{18}\) \(/\)
\(\texttt{8}\) \(\texttt{30}\) \(10^{10^7}\) \(10^{18}\) \(/\)

對於 \(100\%\) 的數據,滿足 \(1\le n\le 10^{10^7},0\le k\le 10^{18},1\le p\le 10^6+3\)

一句話題意

\(f(n)\) 表示斐波那契數列的第 \(n\) 項,給定整數 \(n,m,p\),求 \(f^{(k)}(n)\bmod p\) 的值。

其中 \(f^{(k)}(n)\) 表示函數 \(f(n)\)\(k\) 次迭代,即 \(f(f(f(\cdots f(n))))\),共有 \(k\) 層。

solution

Subtask 1

\(p=1\),輸出 \(0\) 即可。

Subtask 2

\(k=0\),即沒有嵌套,字符串輸入 \(n\),輸出 \(n\bmod p\) 的值即可。

Subtask 3

\(k=1\),即只嵌套一次,用矩陣乘法(或直接遞推),直接算出 \(f(n)\bmod p\) 的值即可。

Subtask 4

出題人也不知道為什么要設這個點。

Subtask 5

為方便,設 \(t_0=p\)

容易發現,斐波那契數列在模意義下是有周期的,並且一定存在一個整數 \(m(2\le m\le p^2)\),使得 \(f(m)\equiv f(1)\pmod p,f(m+1)\equiv f(2)\pmod p\),因此我們設 \(f(n)\bmod t_0\) 意義下的周期為 \(t_1\)\(f^{(k)}(n)\bmod t_0=f(f^{(k-1)}(n)\bmod t_1)\bmod t_0\)

同理,一直進行下去,可以得到答案為 \(f(\cdots f(n\bmod t_k)\bmod t_{k-1}\cdots)\bmod t_0\)

用矩陣乘法單次斐波那契復雜度為 \(\log p\),共有 \(k\) 層嵌套,每次只需改動模數即可,每次的模數可暴力預處理(此處的復雜度見下),復雜度為 \(O(k\log p)\)

Subtask 6

\(n=1\),嵌套幾層都是 \(1\),輸出 \(1\) 即可。

Subtask 7

出題人也不知道為什么要設這個點。

Subtask 8

在上面的基礎上,我們進一步可以發現若有 \(m(m<k)\) 使得 \(t_{m}=t_{m+1}\)\(t_{i}=t_{m}(m\le i\le k)\)

因此在上面暴力算 \(t\) 數組時,算到相同時便可停止,經打表,\(m<25,t_m<10^7\)

對於 \(k\) 范圍的擴大,我們會發現 \(t_i(m\le i\le k)\) 均相同。因此我們可以使用相同的方法,從內向外按上面的方法計算,當其嵌套 \(q\) 層與 \(r(q>r)\) 層相同時,便又產生了一個新的周期,這個周期的長度由抽屜原理可知,與模數(即 \(t_m\))同階。

所以最終復雜度為 \(O(p\log p)\)

std

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int N=1e6+3,K=25,Len=1e7+5;
long long n,k,mod,ans;
int t[K],id,id2,len;
char s[Len];
int book[Len];
const int siz=2;
struct mat
{
    long long a[siz][siz];
    mat(){memset(a,0,sizeof(a));}
    mat operator*(mat x)
    {
        mat ans;
        long long r;
        for(int i=0;i<siz;i++)
        {
            for(int k=0;k<siz;k++)
            {
                r=a[i][k];
                for(int j=0;j<siz;j++)
                {
                    ans.a[i][j]+=x.a[k][j]*r;
                    ans.a[i][j]%=mod;
                }
            }
        }  
        return ans;
    }
    mat operator^(long long x)
    {
        mat ans,base;
        for(int i=0;i<siz;i++) ans.a[i][i]=1;
        for(int i=0;i<siz;i++)
        {
            for(int j=0;j<siz;j++) base.a[i][j]=a[i][j]%mod;
        }
        while(x)
        {
            if(x&1) ans=ans*base;
            base=base*base;
            x>>=1;
        }
        return ans;
    }
};
long long fib(long long x)
{
    if(x==0) return 0;
    if(x==1||x==2) return 1;
    mat f,g;
    f.a[0][0]=f.a[0][1]=1;
    g.a[0][0]=g.a[0][1]=g.a[1][0]=1;
    f=f*(g^(x-2));
    return f.a[0][0];
}
void calc()
{
    for(int i=0;i<=k-1;i++)
    {
        long long a=1%t[i],b=2%t[i],c;
        t[i+1]=1;
        while((a!=1%t[i])||(b!=1%t[i]))
        {
            c=(a+b)%t[i];
            a=b;
            b=c;
            t[i+1]++;
        }
        if(t[i]==t[i+1])
        {
            id=i;
            return;
        }
    }
}
inline long long read()
{
	long long x=0,f=1;
    char ch=getchar();
	while(!isdigit(ch))
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
	while(isdigit(ch))
    {
        x=x*10+ch-48;
        ch=getchar();
    }
	return x*f;
}
signed main()
{
    scanf("%s",s+1);
    n=0;
    id=id2=k=read();
    mod=read();
    t[0]=mod;
    calc();
    len=strlen(s+1);
    for(int i=1;i<=len;i++)
    {
        if(k>=id) n=(n*10+s[i]-48)%t[id];
        else n=(n*10+s[i]-48)%t[k];
    }
    if(k==0)
    {
        printf("%lld\n",n);
        return 0;
    }
    ans=n;
    book[ans]=1;
    mod=t[id];
    for(long long i=k-1;i>=id;i--)
    {
        ans=fib(ans);
        if(book[ans])
        {
            id2=k-i-book[ans]+1;
            break;
        }
        book[ans]=k-i+1;
    }
    k=(k-id-book[ans]+1)%id2+id+book[ans]-1;
    for(int i=k-1;i>=0;i--)
    {
        if(i>=id) mod=t[id];
        else mod=t[i];
        ans=fib(ans);
    }
    printf("%lld\n",ans);
    return 0;
}

后話

吐槽

第一次出有難度的題。(上回那個是 \(\texttt{ycx}\)\(\texttt{idea}\)

碼量小、思維套路的簽到題。

部分分不太好設,因此是亂設的。不過這題這么水應該用不到。

如果有人被卡常,我深表遺憾。

(這話怎么這么熟悉)

本來驗題的時候 \(\texttt{ycx}\) 發現可以用 Pollard Rho 算法來優化,使得 \(p\) 的范圍擴大,並且使用高精來使得 \(k\)\(n\) 同階,但在良心出題人 \(\texttt{zkx}\) 的勸阻下,棄了這個想法。(主要是沒時間)

另外你們有沒有發現,這題的英文名稱叫做 \(while\),其實也在暗示此題的雙重循環節(bushi

總結

\(32\times 1+17\times 1+1\times 1+0\times 3=50\)

平均得分:\(8.33\)

略低於預期,話說為什么連一分都不想拿啊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM