2017多校聯合第一場 1006題 hdu 6038 Function 迴圈節
題意:
Please calculate the quantity of different functions f satisfying
that f(i)=bf(ai) for
each i from 0 to n−1.
(嗯...就是這樣)
思路:
首先可以將 a 陣列劃分成若干個迴圈節,每個節是相互獨立的,取其中一個節來看,令其長度為 l
顯然,由定義,該節就決定了 bx = y, by = z, ... bxx = x, 的這個迴圈節有多長,
再看 b,顯然我們應該將 b 的迴圈節 (設長度為 l0) 對應賦給上述迴圈節,至於長度呢,
1. l0 == l,顯然可行,總共有 l 種排列
2. l0 == 1, 顯然可行,注意到,此時第一個所賦的值決定了這 l 個式子的值,
即,若賦了 bx = x, 則接下來 l - 1 個式子必然也都是 bx = x, 因為第一個式子決定了 y = x, 繼續下去, z = y, 以此類推,
故對每種賦值方法,有且只有 1 種排列,
3. 根據第二點就很容易想到了,l 的所有約數長度的迴圈節都是可以的,並且第一整段 l0 長度的式子決定了後面若干個整段 l0 長度的式子(和第一整段均一模一樣),
故,一旦選定了b的某個迴圈節,且一旦確定了第一整段的排列,那麼長度為 l 的整段的排列都唯一確定了,
而第一整段的排列有 l0 種,
答案就是
AC程式碼如下:
#include <cstdio> #include <cmath> #include <cstring> #define mod 1000000007 #define maxn 100010 typedef long long LL; int kas, a[maxn], b[maxn], n, m; LL tot[maxn]; bool in[maxn]; void findcycle(int* a, int n) { for (int i = 0; i < n; ++i) { if (!in[i]) { in[i] = true; int ii = a[i], cnt = 1; while (ii != i) { in[ii] = true; ii = a[ii]; ++cnt; } ++tot[cnt]; } } } void work() { for (int i = 0; i < n; ++i) scanf("%d", &a[i]); for (int i = 0; i < m; ++i) scanf("%d", &b[i]); memset(tot, 0, sizeof(tot)); memset(in, 0, sizeof(in)); findcycle(b, m); memset(in, 0, sizeof(in)); LL ans = 1; for (int i = 0; i < n; ++i) { if (!in[i]) { in[i] = true; int ii = a[i], cnt = 1; while (ii != i) { // printf("%d ", ii); in[ii] = true; ii = a[ii]; ++cnt; } // printf("\n"); // printf("%d %d\n", i, cnt); LL mul = 0; for (int j = 1; j <= cnt; ++j) { if (cnt % j == 0) { mul += (tot[j] * j) % mod; mul %= mod; } } ans *= mul; ans %= mod; } } printf("Case #%d: %lld\n", ++kas, ans % mod); } int main() { while (scanf("%d%d\n", &n, &m) != EOF) work(); return 0; }
怎麼說呢, 雖然有點馬後炮...
然而,這道題應該還是挺好做的
主要是當時太浮躁,
一來認為自己做不出來
二來被前面 02 WA了太多次很喪氣
三來感覺當時做得人並不太多(也不知哪來的錯覺...
四來就是其它一些瑣碎的原因了...
其實主要吧...還就是不想做(嘆氣
結束之後定下來想了一想,很快就想得八九不離十了...
嗯...挺遺憾的......
接下來都要振作起來啊