2024.9.2雜記

Cocoicobird發表於2024-09-21

洛谷P1990 覆蓋牆壁

題目描述

你有一個長為 \(N\) 寬為 \(2\) 的牆壁,給你兩種磚頭:一個長 \(2\)\(1\),另一個是 L 型覆蓋 \(3\) 個單元的磚頭。如下圖:

0  0
0  00

磚頭可以旋轉,兩種磚頭可以無限制提供。你的任務是計算用這兩種來覆蓋 \(N\times 2\) 的牆壁的覆蓋方法。例如一個 \(2\times3\) 的牆可以有 \(5\) 種覆蓋方法,如下:

012 002 011 001 011  
012 112 022 011 001

注意可以使用兩種磚頭混合起來覆蓋,如 \(2\times4\) 的牆可以這樣覆蓋:

0112
0012

給定 \(N\),要求計算 \(2\times N\) 的牆壁的覆蓋方法。由於結果很大,所以只要求輸出最後 \(4\) 位。例如 \(2\times 13\) 的覆蓋方法為 \(13465\),只需輸出 \(3465\) 即可。如果答案少於 \(4\) 位,就直接輸出就可以,不用加前導 \(0\),如 \(N=3\) 時輸出 \(5\)

輸入格式

一個整數 \(N\),表示牆壁的長。

輸出格式

輸出覆蓋方法的最後 \(4\) 位,如果不足 \(4\) 位就輸出整個答案。

樣例 #1

輸入樣例 #1

13

輸出樣例 #1

3465

提示

資料保證,\(1\leq N\leq 1000000\)

解題思路

解題方法來自 info___tion

假設 \(f_n\) 表示前 \(n\) 列被鋪滿的方案數,則

  • 當前 \(n-1\) 列被鋪滿,鋪滿前 \(n\) 列方案數為 \(f_{n-1}\),這時只能放置豎立的磚頭;

  • 當前 \(n-2\) 列被鋪滿,鋪滿前 \(n\) 列方案數為 \(f_{n-2}\),這時只能放置橫著的磚頭;倘若放置豎立的磚頭,則和上一個重複;

  • 假設 \(g_n\) 表示前 \((n+1)\) 列被鋪滿的,但目前第 \((n+1)\) 列未被鋪滿的方案數,則有兩種情況,一種是該列上面缺失,另一種是該列下面缺失,則鋪滿前 \(n\) 列有 \(2 * g_{n-2}\)

    • 維護 \(g_n\),要麼是後面補了一個橫著的磚頭,要麼是補了一個 \(L\) 型磚頭,因此 \(g_n=g_{n-1}+f_{n-1}\)

C++程式碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1000010, M = 10000;
typedef long long LL;

int n;
int f[N], g[N];

int main() {
    cin >> n;
    f[0] = 1, g[0] = 0, f[1] = g[1] = 1;
    for (int i = 2; i <= n; i++) {
    	f[i] = ((f[i - 1] + f[i - 2]) % M + 2 * g[i - 2] % M) % M;
    	g[i] = (g[i - 1] + f[i - 1]) % M;
    }
    cout << f[n];
    return 0;
}

洛谷P3612 [USACO17JAN] Secret Cow Code S

題面翻譯

奶牛正在試驗秘密程式碼,並設計了一種方法來建立一個無限長的字串作為其程式碼的一部分使用。

給定一個字串,對字串進行一次操作(每一次正確的操作,最後一個字元都會成為新的第一個字元),然後把操作後的字串放到操作前的字串的後面。也就是說,給定一個初始字串,之後的每一步都會增加當前字串的長度。

給定初始字串和 \(N\),請幫助奶牛計算無限字串中位置為 \(N\) 的字元。

第一行輸入一個字串。該字串包含最多 \(30\) 個大寫字母,資料保證 \(N \leq 10^{18}\)

第二行輸入 一個整數 \(N\)。請注意,資料可能很大,放進一個標準的 \(32\) 位整數容器可能不夠,所以你可能要使用一個 \(64\) 位的整數容器(例如,在 C/C++ 中是 long long)。

請輸出從初始字串生成的無限字串中的下標為 \(N\) 的字元。第一個字元的下標是 \(N=1\)

感謝 @y_z_h 的翻譯

題目描述

The cows are experimenting with secret codes, and have devised a method for creating an infinite-length string to be used as part of one of their codes.

Given a string \(s\), let \(F(s)\) be \(s\) followed by \(s\) "rotated" one character to the right (in a right rotation, the last character of \(s\) rotates around and becomes the new first character). Given an initial string \(s\), the cows build their infinite-length code string by repeatedly applying \(F\); each step therefore doubles the length of the current string.

Given the initial string and an index \(N\), please help the cows compute the character at the \(N\)th position within the infinite code string.

輸入格式

The input consists of a single line containing a string followed by \(N\). The string consists of at most 30 uppercase characters, and \(N \leq 10^{18}\).

Note that \(N\) may be too large to fit into a standard 32-bit integer, so you may want to use a 64-bit integer type (e.g., a "long long" in C/C++).

輸出格式

Please output the \(N\)th character of the infinite code built from the initial string. The first character is \(N=1\).

樣例 #1

樣例輸入 #1

COW 8

樣例輸出 #1

C

提示

In this example, the initial string COW expands as follows:


COW -> COWWCO -> COWWCOOCOWWC

解題思路

分治。

對於一個長度為 \(2n\) 的字串 \(S\),可知 \(S_n=S_{n+1}\)\(S_i=S_{i+n+1}\ (1\le i \le n-1)\),因此根據此可以將大問題劃分為小問題。

  • 如果 \(t\) 位於 \(n+1\),則相當於求解 \(t-1\) 處的字元;

  • 如果 \(t\) 位於 \([n+2,2n]\),則求解 \(t-(n+1)\) 的字元,而 \(n=S.length * 2^{x}\)

C++程式碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 10000;
typedef long long LL;

string S;
LL n, length;

void dfs(LL n) {
	if (n <= length) {
		cout << S[n - 1];
		return;
	}
	LL i = length;
	while ((i << 1) < n) i <<= 1;
	n -= (i + 1);
	if (n == 0) n = i;
	dfs(n);
}

int main() {
	cin >> S >> n;
	length = S.size();
	dfs(n);
    return 0;
}