1. 程式人生 > >[補檔]2017-7-26 大佬講課筆記

[補檔]2017-7-26 大佬講課筆記

傳送門 例如 get ati main span struct string 級別

AntiLeaf大佬來講課啦

完全 不可做 題的一天

NOI2016 區間

大佬填坑= = http://cogs.pro/cogs/problem/problem.php?pid=2406 把所有區間按長度排序,從小到大掃每個區間 顯然最長的那個區間一定是隨最小的區間單調增的,因此暴力拓展每個區間並用線段樹求一下是否有被m個區間覆蓋的點即可 O(nlogn)

正經的主題——概率與期望

基本工具

DP&&Gauss DP的狀態定義常常體現“逆序”的特點 狀態之間不存在先後關系時往往需要解方程組 ~~特殊方程組的奇技淫巧= =~~

bzoj1426

http://www.lydsy.com/JudgeOnline/problem.php?id=1426 n種易拉罐,買第i次需要i元,假設每次買到的易拉罐種類都是隨機的,問期望花多少錢能集齊所有易拉罐 n<=5×10^6 (不要問我為啥粘了傳送門還粘題,兩位大佬的題目描述可能是奇奇怪怪的不一樣呢)

本蒟蒻

不就是n×∑(1/i)×average嘛(聽取WA聲一片- -)

AntiLeaf

設購買次數為x,則Ans=(E(x)+E(x2))/2 因為x次,需要x*(x+1)/2元 E(x)=n*∑(1/i) f[i]表示差i種易拉罐的期望次數,g[i]表示平方的期望 f[i]=f[i+1]+n/i 設之前的次數為x,獲得第i種易拉罐還需要y次 E((x+y)2)=E(x2+2xy+y2)=E(x2)+2E(x)E(y)+E(y2) 我們已經知道E(x2)=g[i+1],E(x)=f[i+1],E(y)=n/i 剩下的問題就是如何求E(y2)了 從定義入手 E(y2)=∑(k 1~∞)k2((n-i)/n)^(k-1)×(n/i) 後面的東西硬推出通項(dalao的力量麽= =)

liu_runda

我們可以在得到n種郵票後再計算費用,認為最後一張郵票的花費是1,倒數第二張郵票的花費是2,倒數第n張的花費是n,不難看出這樣計算的費用是不變的. 如果不這樣轉換,也可以認為每一次購買郵票的花費都是1,而每次購買郵票會使後面的每次購買的花費增加1,也就是總費用增加了剩余的購買次數元 F[i]為買最後i張郵票的期望次數,C[i]為買最後i種郵票的期望花費(不包括得到前n-i種郵票使後i種郵票增加的花費) C[i]=(i/n)×衛龍+(1-i/n)×香爆脆(達哥的變量名= =) 問衛龍和香爆脆是什麽 其實就是分類討論 衛龍=1(買1次)+F[i+1](增加的費用)+C[i+1] 香爆脆=1+F[i]+C[i] 最終C[i]=n/i+f[i+1]+C[i+1]+(n-i)*f[i]/i 這個費用提前計算的技巧還是有些用處的. 例如網絡流裏 SCOI2007修車和NOI2012美食節 再次說明概率和期望的題雖然有特性,但是和其他題的思路是相通的. ## 大佬出的水題 有一個人在一個序列上閑逛,初始時這個人位於位置1,每次他有pi的概率停下來(pi只與當前位置有關),也有1-pi的概率繼續走下去(這人閑得慌- -) 如果他走到了序列的某一端,則他下次行走時會掉頭往回走 求這個人走的次數的期望在模10^9+7意義下的結果(意思是必須求出精確解) n<=2*10^5 直接處理這個人來回走的情況可能不太優美,我們可以直接把問題轉化成這個人在一個環上沿固定方向走,把原序列除兩端以外的部分復制一份並反向與原序列拼起來即可 然後考慮環上的問題,定義f[i]表示從i開始走的期望步數,顯然有f[i]=(1-p[i])(f[i+1]+1)(如果這個人按照1~n的方向走的話) 然而這個轉移出環了…… 註意到轉移時的運算都是線性的,因此我們可以從n開始倒推f[i]=a[i]*f[1]+b[i],最後推到f[1]時即可得到一個關於f[1]的一元一次方程,直接解出來即可 顯然這個做法是O(n)的

水題增強版

把剛才的環換成一棵有根樹,每次如果不停下來則會隨機選擇一個兒子走過去,規定走到葉子節點後再走會回到根節點,其余均不變 做法同上 把有根樹換成有根森林,回到根節點改成隨機回到一個根節點,其余均不變 建一個超(chao)級(shi)原點即可,其余做法同上 把有根森林換成DAG,隨機回到一個根節點改成隨機回到一個入度為0的點,其余均不變 建一個新點連向所有入度為0的點,其余做法還是同上……

CF464D World of Darkraft-2

http://codeforces.com/problemset/problem/464/D 翻譯版= =: 你在玩一個遊戲,遊戲中有k種裝備,每件裝備都有一個等級,初始時你擁有每種1級裝備各一件 你打算刷n只怪,每刷一只怪之後系統就會隨機爆出一件裝備 隨機方式是先等概率隨機裝備的種類,設你當前擁有的這種裝備的等級為t,則系統會在1~t+1之間等概率隨機裝備的等級 由於某些原因,你決定只在爆出的裝備高於當前裝備的等級時換上新裝備並賣掉舊裝備,否則直接賣掉爆出的裝備,賣掉等級為t的裝備可以得到t個金幣 求你刷n只怪後得到的金幣數的期望 n<=10^5,k<=100 可以發現每種裝備對答案的貢獻都完全相同且互不影響,因此我們可以只求出一種裝備對答案的貢獻,最後乘上k即可 一種裝備的貢獻可以用DP求解,設f[i,j]表示帶著等級為j的裝備再刷i只怪的期望收益(註意這裏還是逆序定義),則有 f[i,j]=((f[i-1,j]+(j+1)/2)×(j/(j+1))+(f[i-1,j+1]+j)/(j+1))/k+(f[i-1,j]×(k-1))/k (亂成啥了- -) 按照這個方程DP可以做到O(n2) 繼續考慮如何優化 DP的轉移已經無法再優化了,因此我們可以嘗試優化狀態數 註意到裝備等級越高,再提升一級就越難,而刷n只怪之後裝備的期望等級最多也是O(n^0.5)的,並且不難看出等級比O(n^0.5)高太多之後的概率就可以忽略不計了 因此我們可以把第二維的範圍限定為<=一個O(n^0.5)級別的數,這樣就可以把復雜度降到O(n^1.5)了
這道題告訴我們,做不要求輸出精確解的概率/期望DP時可以忽略概率非常小的狀態,通常可以起到卡常的作用,有時也能優化復雜度(比如這道題)

CF696B Puzzles

http://codeforces.com/problemset/problem/696/B 有一棵n個點的有根樹,從根開始對這棵樹進行dfs,對於一個點訪問它的所有兒子的順序是隨機的 求每個點的時間戳的期望 n<=10^5 我們都知道期望有線性性 因此一個點的時間戳的期望=父親的期望+兄弟對它的貢獻+1 對每個兄弟分別考慮,如果這個兄弟比它更早訪問,對它的時間戳的貢獻就是子樹大小 由於是隨機訪問,因此誰在前面的概率都是一樣的 一個點的期望=父親的期望+兄弟子樹大小之和/2+1 技術分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 inline int read(){
 6     int sum(0);
 7     char ch(getchar());
 8     for(;ch<0||ch>9;ch=getchar());
 9     for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar());
10     return sum;
11 }
12 struct edge{
13     int s,e,n;
14 }a[100001];
15 int pre[100001],tot;
16 inline void insert(int s,int e){
17     a[++tot].s=s;
18     a[tot].e=e;
19     a[tot].n=pre[s];
20     pre[s]=tot;
21 }
22 int size[100001],fa[100001];
23 double f[100001];
24 int n;
25 inline void dfs(int u){
26     size[u]=1;
27     for(int i=pre[u];i!=-1;i=a[i].n){
28         int e(a[i].e);
29         dfs(e);
30         size[u]+=size[e];
31     }
32 }
33 inline void cal(int u){
34     if(u!=1)
35         f[u]=f[fa[u]]+(size[fa[u]]-size[u]-1)/2.0+1;
36 //    cout<<u<<‘ ‘<<f[u]<<endl;
37     for(int i=pre[u];i!=-1;i=a[i].n)
38         cal(a[i].e);
39 }
40 int main(){
41     memset(pre,-1,sizeof(pre));
42     n=read();
43     for(int i=2;i<=n;i++){
44         int x(read());
45         fa[i]=x;
46         insert(x,i);
47     }
48     dfs(1);
49     f[1]=1;
50     cal(1);
51     for(int i=1;i<=n;i++)
52         printf("%.1lf ",f[i]);
53 }
54 //首道cf上的題留念- -
View Code

GT考試

https://hzoi-mafia.github.io/2017/07/12/5/ (紀念我死去的github) 大佬告訴我我那個鬼東西叫KMP自動機- - ~~然而我瞎打的時候並不知道自動機= =~~

總結

並不咋能聽懂= = 還需消化吸收= = ps:等我能做出來的時候在粘代碼吧- -

[補檔]2017-7-26 大佬講課筆記