Good Bye 2017 部分題解

2022-08-16 10:33:10 字數 3119 閱讀 2984

\(dp[i][j]\) 表示已有 \(i\) 個 \(a\) 和 \(j\) 個 \(ab\) 的情況下繼續構造能得到的 \(ab\) 個數的期望。

考慮 dfs 記憶化搜尋。

有兩個要注意的地方:

令 \(p_a\) 為新增 \(a\) 的概率,\(p_b\) 為新增 \(b\) 的概率。

當 \(i + j \geq k\) 時,這個情況下新增乙個 \(b\) 構造就停止了,但是在這個 \(b\) 之前顯然可以無限新增 \(a\) ,這後面的期望為 \((i + j) * p_b + p_a*(i+j+1)*p_b+p_a^2*(i+j+2)*p_b+...\) 這個式子可以化簡,\(o(1)\) 計算。

起始狀態應該是 \(dp[0][0] = dp[1][0] * p_a + dp[0][0] * p_b\) ,\(dp[0][0] * p_b\) 說明我們可以不斷新增前導 \(b\) 。可以發現 \(dp[0][0] = (p_b^0+p_b^1+p_b^2...) * dp[1][0] * p_a=\frac*dp[1][0]*p_a=dp[1][0]\),所以我們可以直接計算乙個以 \(a\) 開頭的序列 ,即計算 \(dp[1][0]\) 。

#includeusing namespace std;

const int mod = 1e9 + 7;

long long pow(long long x, int k)

return ret;

}long long k, pa, pb, dp[1001][1001];

long long dfs(int a, int ab)

int main()

官方題解 很詳細了,自己補充幾點。

考慮 \(m\) 個二進位制數,假設 \(m=4\) ,那麼有 0001,0010,0100,1000 。這些數一定是某一二進位制位有 \(1\) 的最小的數,用 \(f\) 表示這個關係。\(f[0]=0001\),\(f[1]=0010\) ... 。這些數中任意兩個數按位與後都為 \(0\) ,那麼可以考慮求這個集合劃分方法的數目,即貝爾數 ,將各個子集中的數分別按位或起來,舉個例子 1000,0100,0011 。這種情況下,第一位和第二位為 \(1\) 的二進位制數都是 0011 ,可以發現,各種劃分方案中我們得到的 \(f\) 並不會完全相同,所以用這個劃分方案數就對應著 \(m\) 位二進位制數的解(具體可見官方題解的證明)。

題目要求 \(t\) 是 \(s\) 的子集。以樣例為例,

11010

00101

11000

豎著去看,有兩個 101 兩個 010 乙個 100 。考慮兩個 101 ,我們再橫著去看,即 00 11 00 ,我們知道乙個 \(k\) 進製數的任意一種方案一定包括 \(k\) 個 \(0\) 和 \(k\) 個 \(1\) 這兩個二進位制數,我們分開去求一定可以得到滿足題目的方案,若 \(b[i]\) 為貝爾數,那麼這個答案就是 \(b[2] * b[2] * b[1]\)。

#includeusing namespace std;

const int n = 1e3 + 10;

const int mod = 1e9 + 7;

long long c[n][n];

mapmp;

long long a[n], b[n], c[n][n];

int main()

}int n, m;

cin >> m >> n;

while(n--)

}for (int i = 0; i < m; i++)

b[0] = b[1] = 1;

for (int i = 2; i <= m; i++)

}long long ans = 1;

for(auto it : mp)

cout << ans << endl;

return 0;

}

以 g 為間隔分組,每個組內單獨討論,要滿足題目條件有兩種連法:

兩個 g 不直接相連,通過連線 b 間接連上,也要通過連線 r 間接連上,花費為兩倍兩個 g 直接的距離。

兩個 g 直接相連,那麼 b 全部連上的話就成了乙個環了,考慮去掉花費最大的一條邊,r 類似。

#includeusing namespace std;

int preg, prer, preb, fr, lr, fb, lb, mxr, mxb;

int main()

if(fb)

} else

prer = p;

preb = p;

preg = p;

lb = lr = p;

mxb = mxr = 0;

} else if(c[0] == 'b') else if(c[0] == 'r')

}if(!preg) else

cout << ans << endl;

return 0;

}

\(dp[i][j][k][o]\) 表示前 \(i\) 個數中有 \(j\) 個大於等於 \(k\) 的數時的構數方案數,\(o\) 為了保證邊界,構造的數不大於 \(x\)。

舉個例子,比方說乙個數 \(3312\) 我們要累積這個數對答案的貢獻,實際上是 \(1233\) ,大於等於 \(1\) 的數有 \(4\) 個,我們可以認為貢獻了 \(1111\) ,大於等於 \(2\) 的數有 \(3\) 個,貢獻了 \(111\) ,大於等於 \(3\) 的數有 \(2\) 個,貢獻了 \(11\) 。

最後列舉 \(k\),累計計算一下答案即可。

#includeusing namespace std;

const int mod = 1e9 + 7;

const int n = 707;

char s[n];

int dp[n][n][10][2];

int main()

for (int i = 0; i < n; i++) }}

}}

long long ans = 0;

for(int k = 1; k < 10; k++)

}printf("%i64d\n", ans);

return 0;

}

練習2部分題解

問題 g 汽水瓶 時間限制 1 sec 記憶體限制 128 mb提交 93 解決 45 201501010119 提交狀態討論版 題目描述 有這樣一道智力題 某商店規定 三個空汽水瓶可以換一瓶汽水。小張手上有十個空汽水瓶,她最多可以換多少瓶汽水喝?答案是5瓶,方法如下 先用9個空瓶子換3瓶汽水,喝掉...

cqoi2015部分題解

只做了前三題。t1 選數 先把題目轉化為求選n個數最大公約數為1,不用說了。假定f i 為選出n個數最大公約數為i的方案數。由於題目中有條件h l 10 5,所以i 10 5即可。令l l 1 i,r h i f i r l n sigma f a i r l 最後的r l為減去全部選擇乙個數的方案...

PA2014部分題解

之前有一些寫過了大概扔在奇奇妙妙的地方 可能翻一下blog能翻得到的 瞎寫一下最近的題吧 2 242 224這個狀壓和爆搜尷尬的地位 90 s90s 90s果斷狀壓了 把包從大到小排序,記乙個pai rpair pair 的d p mask dp mask dp mas k 表示裝完狀態裡的這些東西...