1. 程式人生 > >【UOJ#129】 【NOI2015】壽司晚宴

【UOJ#129】 【NOI2015】壽司晚宴

存在 bsp 給定 輸出 style 同時 文件的 amp 準備

題目描述

為了慶祝 NOI 的成功開幕,主辦方為大家準備了一場壽司晚宴。小 G 和小 W 作為參加 NOI 的選手,也被邀請參加了壽司晚宴。

在晚宴上,主辦方為大家提供了 n−1 種不同的壽司,編號 1,2,3,…,n−1,其中第 i 種壽司的美味度為 i+1 (即壽司的美味度為從 2 到 n)。

現在小 G 和小 W 希望每人選一些壽司種類來品嘗,他們規定一種品嘗方案為不和諧的當且僅當:小 G 品嘗的壽司種類中存在一種美味度為 x 的壽司,小 W 品嘗的壽司中存在一種美味度為 y 的壽司,而 x 與 y 不互質。

現在小 G 和小 W 希望統計一共有多少種和諧的品嘗壽司的方案(對給定的正整數 p 取模)。註意一個人可以不吃任何壽司。

輸入格式

輸入文件的第 1 行包含 2 個正整數 n,p,中間用單個空格隔開,表示共有 n 種壽司,最終和諧的方案數要對 p 取模。

輸出格式

輸出一行包含 1 個整數,表示所求的方案模 p 的結果。

題解

註意到所有和諧的方案,兩人的質數集合一定是不相交的。

對於所有大於根號的質數,不存在一個數同時包含兩個這樣的數。打個比方,假如n是100,那麽我們在考慮17的時候,就不需要考慮11,13有沒有取。而小於根號的質數就不具備有這個性質。所以對於大於根號的質數是一個分層的關系,層與層之間是無後效性的,所以我們可以分層來DP。

計f[i][A][B]表示在第i層裏一個人集合為A,另一個人集合為B的方案。然後枚舉子集、前綴和轉移一下就好了。

代碼

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 #define R register
 6 #define maxn 510
 7 int pr[maxn], prcnt, mp[maxn], r[maxn];
 8 int f[maxn][256][256][2], g[maxn][256][256], tf[256][256][2];
 9 bool vis[maxn];
10 inline bool cmp(R int a, R int
b) 11 { 12 return mp[a] < mp[b]; 13 } 14 int main() 15 { 16 R int n, p; scanf("%d%d", &n, &p); 17 for (R int i = 2; i <= n; ++i) 18 { 19 r[i] = i; 20 if (!vis[i]) pr[++prcnt] = mp[i] = i; 21 for (R int j = 1; j <= prcnt && i * pr[j] <= n; ++j) 22 { 23 vis[i * pr[j]] = 1; 24 mp[i * pr[j]] = mp[i]; 25 if (i % pr[j] == 0) break; 26 } 27 } 28 std::sort(r + 2, r + n + 1, cmp); 29 R int tot = 0; 30 g[0][0][0] = 1 % p; 31 for (R int i = 2; i <= n; ++i) 32 { 33 R int x = r[i], tS = 0; 34 if (mp[x] < 20 || mp[r[i]] != mp[r[i - 1]]) ++tot; 35 // printf("%d %d %d %d\n", i, r[i], mp[r[i]], tot); 36 for (R int j = 1; j <= prcnt && pr[j] < 20; ++j) 37 if (x % pr[j] == 0) tS |= 1 << (j - 1); 38 39 memcpy(tf, f[tot], sizeof (tf)); 40 for (R int A = 0; A < 256; ++A) 41 { 42 R int mB = ~A & 255; 43 for (R int B = mB; B; B = (B - 1) & mB) 44 if (!(B & tS)) 45 (f[tot][A | tS][B][0] += (g[tot - 1][A][B] + tf[A][B][0]) % p) %= p, 46 (f[tot][B][A | tS][1] += (g[tot - 1][B][A] + tf[B][A][1]) % p) %= p; 47 (f[tot][A | tS][0][0] += (g[tot - 1][A][0] + tf[A][0][0]) % p) %= p; 48 (f[tot][0][A | tS][1] += (g[tot - 1][0][A] + tf[0][A][1]) % p) %= p; 49 } 50 51 for (R int A = 0; A < 256; ++A) 52 { 53 R int mB = ~A & 255; 54 for (R int B = mB; B; B = (B - 1) & mB) 55 g[tot][A][B] = (g[tot - 1][A][B] + (f[tot][A][B][0] + f[tot][A][B][1]) % p) % p; 56 g[tot][A][0] = (g[tot - 1][A][0] + (f[tot][A][0][0] + f[tot][A][0][1]) % p) % p; 57 } 58 } 59 R int ans = 0; 60 for (R int A = 0; A < 256; ++A) 61 { 62 R int mB = ~A & 255; 63 for (R int B = mB; B; B = (B - 1) & mB) 64 (ans += g[tot][A][B]) %= p; 65 (ans += g[tot][A][0]) %= p; 66 } 67 printf("%d\n", ans); 68 return 0; 69 }

【UOJ#129】 【NOI2015】壽司晚宴