\(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]\)。
以 g 為間隔分組,每個組內單獨討論,要滿足題目條件有兩種連法:#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 不直接相連,通過連線 b 間接連上,也要通過連線 r 間接連上,花費為兩倍兩個 g 直接的距離。
兩個 g 直接相連,那麼 b 全部連上的話就成了乙個環了,考慮去掉花費最大的一條邊,r 類似。
\(dp[i][j][k][o]\) 表示前 \(i\) 個數中有 \(j\) 個大於等於 \(k\) 的數時的構數方案數,\(o\) 為了保證邊界,構造的數不大於 \(x\)。#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;
}
舉個例子,比方說乙個數 \(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 表示裝完狀態裡的這些東西...