高一上六月下旬日记
6.27
闲话
- 下午返校了,在校门口取新高一的校服。试穿时用力太大不小心将左眼镜腿掰折了一截,因为着急进校,就凑活用了。
- 进校后回 \(1506\) 发现我的行李从上铺搬到了下铺,摊在床上,稍微值点钱的东西都没了,包括但不限于肥皂、洗衣粉、两大袋零食、指甲剪、风油精、剪刀、湿巾、锁加两个钥匙、鞋套、花露水、鞋垫、水杯、雨伞、卫生纸。
- 以为是单独取食堂办饭卡,但失败了,遇到其他奥赛的一问才知道取找奥赛教练要饭卡,遂回机房取饭卡。
- 机房 \(ftp\) 开开了,【数据删除】没动,@wkh2008 称其是“钓鱼执法”。
- 晚上 \(field\) 说了下作息时间表,还说要给我们打印一份贴墙上,但直到放学也没看见作息时间表。
- \(field\) 称等高中的分完班后我们就搬到本部去,让我们做好心理准备。
- \(field\) 在机房收手机放到了“机柜”(机房的柜子),说把手机放到“宿柜”(宿舍的柜子)容易被查。
- 晚休一开始是数奥教练查宿,“信息的那几个快点啊”,后面没有宿管来。
做题纪要
luogu P10495 阶乘分解
-
筛出 \(1 \sim n\) 的所有素数 \(\{ p \}\) ,设其共有 \(m\) 个,则 \(n!=\prod\limits_{i=1}^{m}p_{i}^{\sum\limits_{j=1}^{\left\lfloor \log_{p_{i}} n \right\rfloor} \left\lfloor \frac{n}{p_{i}^{j}} \right\rfloor}\) 。
点击查看代码
int prime[1000010],len=0; bool vis[1000010]; void isprime(int n) { memset(vis,false,sizeof(vis)); for(int i=2;i<=n;i++) { if(vis[i]==false) { len++; prime[len]=i; } for(int j=1;j<=len&&i*prime[j]<=n;j++) { vis[i*prime[j]]=true; if(i%prime[j]==0) { break; } } } } int main() { int n,c,i,j; cin>>n; isprime(n); for(i=1;i<=len;i++) { c=0; for(j=1;pow(prime[i],j)<=n;j++) { c+=n/pow(prime[i],j); } cout<<prime[i]<<" "<<c<<endl; } return 0; }
SP2916 GSS5 - Can you answer these queries V
-
设 \(pre_{l,r}\) 表示 \([l,r]\) 的最大左子段和, \(suf_{l,r}\) 表示 \([l,r]\) 的最大右子段和, \(ans_{l,r}\) 表示 \([l,r]\) 的最大右子段和, \(sum_{l,r}\) 表示 \([l,r]\) 的区间和。
-
大力分讨。
- 当 \([x_{1},y_{1}]\) 和 \([x_{2},y_{2}]\) 不相交时,有 \(suf_{x_{1},y_{1}}+sum_{y_{1}+1,x_{2}-1}+pre_{x_{2},y_{2}}\) 即为所求,为保证区间存在故 \(suf_{x_{1},y_{1}}+sum_{y_{1},x_{2}}+pre_{x_{2},y_{2}}-a_{y_{1}}-a_{x_{2}}\) 即为所求。
- 当 \([x_{1},y_{1}]\) 和 \([x_{2},y_{2}]\) 相交时,有 \(\max \{ suf_{x_{1},x_{2}}+pre_{x_{2}+1,y_{2}},ans_{x_{2},y_{1}},suf_{x_{1},y_{1}}+pre_{y_{1}+1,y_{2}} \}\) 即为所求,为保证区间存在故 \(\max \{ suf_{x_{1},x_{2}}+pre_{x_{2},y_{2}}-a_{x_{2}},ans_{x_{2},y_{1}},suf_{x_{1},y_{1}}+pre_{y_{1},y_{2}}-a_{y_{1}} \}\) 即为所求。
点击查看代码
int a[10010]; struct SMT { struct SegmentTree { int l,r,sum,suf,pre,ans; }tree[40010]; int lson(int x) { return x*2; } int rson(int x) { return x*2+1; } void pushup(int rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; tree[rt].pre=max(tree[lson(rt)].pre,tree[lson(rt)].sum+tree[rson(rt)].pre); tree[rt].suf=max(tree[rson(rt)].suf,tree[rson(rt)].sum+tree[lson(rt)].suf); tree[rt].ans=max(tree[lson(rt)].suf+tree[rson(rt)].pre,max(tree[lson(rt)].ans,tree[rson(rt)].ans)); } void build(int rt,int l,int r) { tree[rt].l=l; tree[rt].r=r; if(l==r) { tree[rt].sum=tree[rt].suf=tree[rt].pre=tree[rt].ans=a[l]; return; } int mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } SegmentTree query(int rt,int x,int y) { if(x<=tree[rt].l&&tree[rt].r<=y) { return tree[rt]; } int mid=(tree[rt].l+tree[rt].r)/2; if(y<=mid) { return query(lson(rt),x,y); } else { if(x>mid) { return query(rson(rt),x,y); } else { SegmentTree p=query(lson(rt),x,y),q=query(rson(rt),x,y),num; num.sum=p.sum+q.sum; num.pre=max(p.pre,p.sum+q.pre); num.suf=max(q.suf,q.sum+p.suf); num.ans=max(p.suf+q.pre,max(p.ans,q.ans)); return num; } } } }T; int main() { int t,n,m,x1,y1,x2,y2,i,j; cin>>t; for(i=1;i<=t;i++) { cin>>n; for(j=1;j<=n;j++) { cin>>a[j]; } T.build(1,1,n); cin>>m; for(j=1;j<=m;j++) { cin>>x1>>y1>>x2>>y2; if(y1<x2) { cout<<T.query(1,x1,y1).suf+T.query(1,y1,x2).sum+T.query(1,x2,y2).pre-a[y1]-a[x2]<<endl; } else { cout<<max(T.query(1,x1,x2).suf+T.query(1,x2,y2).pre-a[x2],max(T.query(1,x2,y1).ans,T.query(1,x1,y1).suf+T.query(1,y1,y2).pre-a[y1]))<<endl;; } } } return 0; }
6.28
闲话
- 早上跑操本来在 \(23429\) 班后面跑,我以为站位和初中的一样(竖向),遂直接站到了操场最右侧,到那里的时候一个人也没有,然后数奥教练也是这么认为的,也跟了过来,故没有追究班号的问题。数奥的可能还因此找错了位置,没有一个人来跑操。实际上,高一 \(4\) 部站位是横向的,进跑道也是横向进,把我们看懵了。跑道上统一在外侧没有被拆掉跑道的部分跑,但我们以前都是靠里侧被拆掉跑道的部分跑的,离谱。
- 上午 \(miaomiao\) 给我们放了容斥原理和概率期望 \(DP\) 的视频; \(miaomiao\) 让我们换到
h.普及oj
(一开始是全部搬的GXYZOJ) 上。结果没有 \(MLE\) 的评测信息,全部爆的是 \(RE\) ,和 \(Accoders\) 一个尿性;CF域写的是 \(RMJ\) ,貌似还是借的Hydro;luogu域 \(miaomiao\) 称题太多了,他懒得搬了,让我们需要啥再让他搬。还称“这是你们唯一一次改名字的机会啊”,但他是不知道以前我们经常用readonly=""
改用户名吗? - 中午回宿舍后发现电话还是没通。
- 晚上 \(miaomiao\) 突然问我们 \(LCA\) 会几种写法,问概率期望专题的题是不是有点难,说让我们趁着高中没放假这几天抓紧赶进度,暑假就和他们一起打模拟赛了。
- 晚休数奥教练和 \(miaomiao\) 来查宿;数奥教练说了下明天跑操的站位;我和 \(miaomiao\) 说了下电话的问题,他说跟学校里问问; \(miaomiao\) 问了问我们进度,“明天再给半天还够吗”,“反正你们现在啥没学就赶紧补啊”。
做题纪要
luogu P4316 绿豆蛙的归宿
-
设 \(f_{x}\) 表示从 \(x\) 走到终点所经过的路径的期望长度,状态转移方程为 \(f_{x}=\frac{1}{out_{x}} \times \sum\limits_{(x,y,z) \in E}(f_{y}+z)\) ,边界为 \(f_{n}=0\) 。
-
建反图跑拓扑即可。
点击查看代码
struct node { int nxt,to,w; }e[200010]; int head[200010],din[200010],dout[200010],cnt=0; double f[200010]; void add(int u,int v,int w) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].w=w; head[u]=cnt; } void top_sort(int n) { queue<int>q; int x,i; for(i=1;i<=n;i++) { if(din[i]==0) { q.push(i); } } while(q.empty()==0) { x=q.front(); q.pop(); for(i=head[x];i!=0;i=e[i].nxt) { din[e[i].to]--; f[e[i].to]+=(f[x]+1.0*e[i].w)/dout[e[i].to]; if(din[e[i].to]==0) { q.push(e[i].to); } } } } int main() { int n,m,u,v,w,i; cin>>n>>m; for(i=1;i<=m;i++) { cin>>u>>v>>w; add(v,u,w); din[u]++; dout[u]++; } top_sort(n); printf("%.2lf\n",f[1]); return 0; }
CF451E Devu and Flowers
-
多重集组合数板子。
-
枚举集合后卢卡斯求解即可。
点击查看代码
const ll p=1000000007; ll inv[25],jc_inv[25],a[25]; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } ll C(ll n,ll m,ll p) { if(n>=m&&n>=0&&m>=0) { ll ans=jc_inv[m]; for(ll i=n-m+1;i<=n;i++) { ans=ans*i%p; } return ans; } else { return 0; } } ll lucas(ll n,ll m,ll p) { return m?C(n%p,m%p,p)*lucas(n/p,m/p,p)%p:1; } int main() { ll n,m,ans=0,sum,num,i,s; cin>>n>>m; jc_inv[0]=1; for(i=1;i<=n;i++) { cin>>a[i]; inv[i]=qpow(i,p-2,p); jc_inv[i]=jc_inv[i-1]*inv[i]%p; } for(s=0;s<=(1<<n)-1;s++) { sum=0; num=0; for(i=0;i<=n-1;i++) { if((s>>i)&1) { sum+=(a[i+1]+1); num++; } } ans=(ans+((num%2==0)?1:-1)*lucas(n+m-1-sum,n-1,p)+p)%p; } cout<<ans<<endl; return 0; }
UVA12369 Cards
-
本题中的得到是指目前的牌中包含所要求的牌,而不是目前的牌中恰好是所要求的牌。
-
设 \(f_{a,b,c,d,x,y}\) 表示已经抽了 \(a\) 张黑桃, \(b\) 张红桃, \(c\) 张梅花, \(d\) 张方块,大王/小王的使用状态为 \(x/y\) 时的期望张数。具体地, \(x/y=0 \sim 3\) 分别表示大王/小王视为黑桃、红桃、梅花、方块, \(x/y=4\) 表示未使用大王/小王。
-
状态转移方程为 \(f_{a,b,c,d,x,y}=1+\frac{13-a}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a+1,b,c,d,x,y}+\frac{13-b}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b+1,c,d,x,y}+\frac{13-c}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b,c+1,d,x,y}+\frac{13-d}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times f_{a,b,c,d+1,x,y}+\frac{[x=4]}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times \min\limits_{x'=0}^{3} \{ f_{a,b,c,d,x',y} \}+\frac{[y=4]}{54-a-b-c-d-(x \ne 4)-(y \ne 4)} \times \min\limits_{y'=0}^{3} \{ f_{a,b,c,d,x,y'} \}\) ,需要注意边界处理。
-
记忆化搜索时维护即可。
-
最终,有 \(f_{0,0,0,0,4,4}\) 即为所求。
点击查看代码
int A,B,C,D; double f[20][20][20][20][8][8]; bool vis[20][20][20][20][8][8]; double dfs(int a,int b,int c,int d,int x,int y) { if(vis[a][b][c][d][x][y]==false) { vis[a][b][c][d][x][y]=true; int sum=a+b+c+d+(x!=4)+(y!=4); double minn; if(a>13||b>13||c>13||d>13||sum>54) { f[a][b][c][d][x][y]=0x7f7f7f7f; } else { if(a+(x==0)+(y==0)>=A&&b+(x==1)+(y==1)>=B&&c+(x==2)+(y==2)>=C&&d+(x==3)+(y==3)>=D) { f[a][b][c][d][x][y]=0; } else { f[a][b][c][d][x][y]=1+1.0*(13-a)/(54-sum)*dfs(a+1,b,c,d,x,y) +1.0*(13-b)/(54-sum)*dfs(a,b+1,c,d,x,y) +1.0*(13-c)/(54-sum)*dfs(a,b,c+1,d,x,y) +1.0*(13-d)/(54-sum)*dfs(a,b,c,d+1,x,y); if(x==4) { minn=0x7f7f7f7f; for(int i=0;i<=3;i++) { minn=min(minn,dfs(a,b,c,d,i,y)); } f[a][b][c][d][x][y]+=1.0/(54-sum)*minn; } if(y==4) { minn=0x7f7f7f7f; for(int i=0;i<=3;i++) { minn=min(minn,dfs(a,b,c,d,x,i)); } f[a][b][c][d][x][y]+=1.0/(54-sum)*minn; } } } } return f[a][b][c][d][x][y]; } int main() { int t,i; cin>>t; for(i=1;i<=t;i++) { cin>>A>>B>>C>>D; memset(f,0,sizeof(f)); memset(vis,0,sizeof(vis)); double ans=dfs(0,0,0,0,4,4); cout<<"Case "<<i<<": "; if(ans<=54) { printf("%.3lf\n",ans); } else { cout<<"-1.000"<<endl; } } return 0; }
luogu P10504 守卫者的挑战
-
地图残片的大小为 \(1\) 可以转化为容量为 \(-1\) 的包包,而不用去担心怎么分配的问题。
-
"只需要完成所有 \(n\) 项挑战后背包容量足够容纳地图残片即可"这个条件很重要。
-
设 \(f_{i,j,k}\) 表示当前进行了 \(i\) 次挑战,成功了 \(j\) 次,目前背包剩余容量为 \(k\) 时的概率,状态转移方程为 \(f_{i,j,k}=(1-p_{i}\%) \times f_{i-1,j,k}+p_{i} \% \times f_{i-1,j-1,k-a_{i}}\) ,边界为 \(f_{0,0,k}=1\) 。特别地,对于剩余容量 \(\ge n\) 的情况均可看做剩余容量 \(=n\) 的情况。
-
由于背包容量 \(\in [-n,n]\) ,将数组整体向右平移即可。
-
最终,有 \(\sum\limits_{i=l}^{n}\sum\limits_{j=0}^{n}f_{n,i,j}\) 即为所求。
点击查看代码
int a[202],p[202]; double f[202][202][402]; int main() { int n,l,k,i,j,h; double ans=0; cin>>n>>l>>k; for(i=1;i<=n;i++) { cin>>p[i]; } for(i=1;i<=n;i++) { cin>>a[i]; } f[0][0][200+min(k,n)]=1; for(i=0;i<=n;i++) { for(j=0;j<=i;j++) { for(h=200-n;h<=200+n;h++) { f[i+1][j][h]+=(1.0-p[i+1]/100.0)*f[i][j][h]; f[i+1][j+1][min(200+n,h+a[i+1])]+=p[i+1]/100.0*f[i][j][h]; } } } for(i=l;i<=n;i++) { for(j=200;j<=200+n;j++) { ans+=f[n][i][j]; } } printf("%.6lf\n",ans); return 0; }
LightOJ 1248.Dice (III)
-
设 \(f_{i}\) 表示已经看到 \(i\) 面不同的面时还需要的期望次数,有 \(f_{i}=1+\frac{i}{n} \times f_{i}+\frac{n-i}{n} \times f_{i+1}\) ,移项得到状态转移方程 \(f_{i}=f_{i+1}+\frac{n}{n-i}\) ,边界为 \(f_{n}=0\) 。
-
最终,有 \(f_{0}\) 即为所求。
点击查看代码
double f[100010]; int main() { int t,n,i,j; cin>>t; for(i=1;i<=t;i++) { cin>>n; f[n]=0; for(j=n-1;j>=0;j--) { f[j]=f[j+1]+1.0*n/(n-j); } printf("Case %d: %.8lf\n",i,f[0]); } return 0; }
LightOJ 1030.Discovering Gold
-
设 \(a_{i}\) 表示第 \(i\) 个格子的黄金数量, \(f_{i}\) 表示当前在第 \(i\) 个格子,到达第 \(n\) 个格子的期望黄金数量,状态转移方程为 \(f_{i}=a_{i}+\sum\limits_{j=i+1}^{\min(i+6,n)}\frac{f_{i+j}}{\min(6,n-i)}\) 。
-
最终,有 \(f_{1}\) 即为所求。
点击查看代码
int a[110]; double f[110]; int main() { int t,n,i,j,k; cin>>t; for(i=1;i<=t;i++) { cin>>n; for(j=1;j<=n;j++) { cin>>a[j]; } for(j=n;j>=1;j--) { f[j]=a[j]; for(k=j+1;k<=min(j+6,n);k++) { f[j]+=f[k]/(1.0*min(6,n-j)); } } printf("Case %d: %.8lf\n",i,f[1]); } return 0; }
CF453A Little Pony and Expected Maximum
-
设掷 \(n\) 次骰子后的最大值为 \(k\) ,则方案数为 \(k^{n}-(k+1)^{n}\) 。
-
最终,有 \(\sum\limits_{i=1}^{m}\dfrac{(i^{n}-(i-1)^{n})}{m^{n}} \times i=\sum\limits_{i=1}^{m}((\dfrac{i}{m})^{n}-(\dfrac{i-1}{m})^{n}) \times i\) 即为所求。
点击查看代码
int main() { double m,n,ans=0; cin>>m>>n; for(int i=1;i<=m;i++) { ans+=1.0*i*(pow(1.0*i/m,n)-pow(1.0*(i-1)/m,n)); } printf("%.8lf\n",ans); return 0; }
CF696B Puzzles
-
目前在 \(fa\) 节点时,搜到子节点 \(x\) 和其他子节点的概率是相等的(因为不需要管具体是哪个节点),均为 \(\frac{1}{2}\) 。
-
设 \(f_{x}\) 表示 \(x\) 时间戳的期望值,状态转移方程为 \(f_{x}=1+f_{fa}+\frac{siz_{fa}-1-siz_{x}}{2}\) ,边界为 \(f_{1}=1\) 。
点击查看代码
struct node { int nxt,to; }e[100010]; int head[100010],siz[100010],cnt=0; double f[100010]; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x) { siz[x]=1; for(int i=head[x];i!=0;i=e[i].nxt) { dfs(e[i].to); siz[x]+=siz[e[i].to]; } } void reroot(int x) { for(int i=head[x];i!=0;i=e[i].nxt) { f[e[i].to]=1+f[x]+(siz[x]-1-siz[e[i].to])/2.0; reroot(e[i].to); } } int main() { int n,u,v,i; cin>>n; for(i=2;i<=n;i++) { cin>>u; v=i; add(u,v); } dfs(1); f[1]=1; reroot(1); for(i=1;i<=n;i++) { printf("%.6lf ",f[i]); } return 0; }
luogu T459661 [CL-9G-ddd] 灯灯灯
-
先考虑绿灯全部熄灭的情况,最后被熄灭的一定是绿灯,设还剩下 \(i(1 \le i \le n)\) 盏红灯,那么先前的 \(n-i+m-1\) 盏灯的开灯顺序是未知的,将红、绿灯视作 \(01\) 串,总方案数为 \(\dbinom{n-i+m-1}{n-i}\) ,概率为 \(\frac{\binom{n-i+m-1}{n-i}}{\binom{n+m}{n}}\) ,期望为 \(\frac{\binom{n-i+m-1}{n-i}}{\binom{n+m}{n}} \times i\) 。
-
红灯同理,期望为 \(\frac{\binom{n-1+m-i}{m-i}}{\binom{n+m}{n}} \times i\) 。
-
最终,有 \(\frac{\sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i}+\sum\limits_{i=1}^{m}i \times \binom{n-1+m-i}{m-i}}{\binom{n+m}{n}}=\frac{n}{m+1}+\frac{m}{n+1}\) 即为所求。
- 证明
- 先只看前半部分的 \(\sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i}\) ,有 \(\begin{aligned} \sum\limits_{i=1}^{n}i \times \binom{n-i+m-1}{n-i} &=\sum\limits_{i=1}^{n}\binom{n-i+m-1}{n-i}+\sum\limits_{i=1}^{n}(i-1) \times \binom{n-i+m-1}{n-i} \\ &=\binom{n+m-1}{n-1}+\sum\limits_{i=1}^{n-1}i \times \binom{n-i+m-2}{n-i-1} \\ &=\dots \\ &=\sum\limits_{i=1}^{n}\binom{n+m-i}{n-i} \\ &=\binom{n+m}{n-1} \end{aligned}\) ,除以 \(\dbinom{n+m}{n}\) 后得 \(\dfrac{n}{m+1}\) 。
- 同理,后半部分得到 \(\dfrac{m}{n+1}\) 。
点击查看代码
int main() { int n,m; cin>>n>>m; printf("%.6lf\n",1.0*n/(m+1)+1.0*m/(n+1)); return 0; }
- 证明
luogu P1365 WJMZBMR打osu! / Easy
-
多倍经验: CF235B Let's Play Osu!
-
设 \(f_{i}\) 表示以 \(i\) 结尾的期望得分, \(len_{i}\) 表示以 \(i\) 结尾的极大的连续的
o
的期望长度,状态转移方程为 \(\begin{cases} len_{i}=len_{i-1}+1,f_{i}=f_{i-1}+(len_{i-1}+1)^{2}-len_{i-1}^{2}=f_{i-1}+2len_{i-1}+1 & s_{i}='o' \\ len_{i}=0,f_{i}=f_{i-1} & s_{i}='x' \\ len_{i}=\frac{len_{i-1}+1}{2},f_{i}=f_{i-1}+\frac{(len_{i-1}+1)^{2}-len_{i-1}^{2}}{2}=f_{i-1}+\frac{2len_{i-1}+1}{2} & s_{i}='?' \end{cases}\) 。 -
最终,有 \(f_{n}\) 即为所求。
点击查看代码
double f[300010],len[300010]; char s[300010]; int main() { int n,i; cin>>n>>(s+1); for(i=1;i<=n;i++) { if(s[i]=='o') { len[i]=len[i-1]+1; f[i]=f[i-1]+2*len[i-1]+1; } if(s[i]=='x') { len[i]=0; f[i]=f[i-1]; } if(s[i]=='?') { len[i]=(len[i-1]+1)/2.0; f[i]=f[i-1]+(2*len[i-1]+1)/2.0; } } printf("%.4lf\n",f[n]); return 0; }
牛客 NC274855 三角形
-
桶统计即可。
点击查看代码
int a[110],vis[110]; int main() { int n,sum=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; vis[a[i]]++; sum+=(vis[a[i]]>=3); } if(sum>=1) { cout<<"YES"<<endl; } else { cout<<"NO"<<endl; } return 0; }
牛客 NC274857 好数组
-
解下绝对值不等式,发现在 \(a_{i}=0(a_{i} \le a_{j})\) 时原式不成立。
点击查看代码
int main() { int n,x,flag=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>x; flag|=(x==0); } if(flag==0) { cout<<"YES"<<endl; } else { cout<<"NO"<<endl; } return 0; }
牛客 NC274862 前缀平方和序列
- 序列内部的数都是正整数这个条件很好,说明前缀和是递增的(即已有顺序)。 \(1 \sim x\) 中的完全平方数共有 \(\left\lfloor \sqrt{x} \right\rfloor\) 个,从中选出 \(n\) 个,总方案数为 \(\frac{A_{\left\lfloor \sqrt{x} \right\rfloor}^{n}}{A_{n}^{n}}=\dbinom{\left\lfloor \sqrt{x} \right\rfloor}{n}\) 。
-
如果没有序列内部的数都是正整数这个条件,则等价于求多重集的排列。
点击查看代码
const ll p=1000000007; ll qpow(ll a,ll b,ll p) { ll ans=1; while(b>0) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } ll C(ll n,ll m,ll p) { if(n>=m&&n>=0&&m>=0) { ll a=1,b=1; for(ll i=n-m+1;i<=n;i++) { a=a*i%p; } for(ll i=1;i<=m;i++) { b=b*i%p; } return a*qpow(b,p-2,p)%p; } else { return 0; } } int main() { ll n,x; cin>>n>>x; cout<<C(sqrt(x),n,p)<<endl; return 0; }
-
牛客 NC274864 走一个大整数迷宫
-
由 \(p^{k} \equiv 1 \bmod{(p-1)}\) ,得出 \(c_{i,j}=a_{i,j} \times p^{2^{b_{i,j}}} \equiv a_{i,j} \bmod{(p-1)}\) 。
-
\(BFS\) 过程中额外记录一个状态表示计数器 \(\mod{(p-1)}\) 的余数,时空复杂度为 \(O(nmp)\) 。
点击查看代码
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}},vis[15][15][10010],a[15][15]; struct node { int x,y,s,sum; }; int bfs(int x,int y,int n,int m,int p) { int nx,ny,ns; queue<node>q; q.push(node{x,y,a[x][y]%p,0}); vis[x][y][a[x][y]%p]=1; while(q.empty()==0) { node z=q.front(); q.pop(); if(z.x==n&&z.y==m&&z.s==0) { return z.sum; } for(int i=0;i<=3;i++) { nx=z.x+dir[i][0]; ny=z.y+dir[i][1]; ns=(z.s+a[nx][ny])%p; if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&vis[nx][ny][ns]==0) { vis[nx][ny][ns]=1; q.push(node{nx,ny,ns,z.sum+1}); } } } return -1; } int main() { int n,m,p,i,j; cin>>n>>m>>p; for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { cin>>a[i][j]; } } cout<<bfs(1,1,n,m,p-1)<<endl; return 0; }
6.29
闲话
- 早上跑操顺序在 \(23405\) 班后面,来的是数奥教练和另一个不认识的老师,数奥教练还远远得问 \(miaomiao\) 去哪里了。
- 上午 @STA_Morlin 因在机房睡觉被 \(feifei\) \(D\) 了。
- 偶然看见机房外面的垃圾桶里有一个TH的纸袋。
- 下午来机房后碰见原班主任了;回机房后 \(huge\) 给放了每日一歌(事前没有通知),时间和初三的时候一样,用的是电脑音箱;没体活。
- 晚上 @STA_Morlin 因在机房睡觉被 \(huge\) \(D\) 了。
- 晚休的时候泡了桶泡面,没有人来查宿。
做题纪要
luogu P1654 OSU!
-
由于 \(E(x^{2}) \ne E^{2}(x)\) ,故需要额外维护 \(E(x^{2})\) 的贡献。
-
\((x+1)^{3}-x^{3}=3x^{2}+3x+1\) 。
-
状态转移方程为 \(\begin{cases} x_{i}=(x_{i-1}+1) \times p_{i} \\ x'^{2}_{i}=(x'^{2}_{i-1}+2x_{i-1}+1) \times p_{i} \\ f_{i}=f_{i-1}+(3x'^{2}_{i-1}+3x_{i-1}+1) \times p_{i} \end{cases}\) 。
点击查看代码
double f[100010],len1[100010],len2[100010]; int main() { int n,i; double p; cin>>n; for(i=1;i<=n;i++) { cin>>p; len1[i]=(len1[i-1]+1)*p; len2[i]=(len2[i-1]+2*len1[i-1]+1)*p; f[i]=f[i-1]+(3*len2[i-1]+3*len1[i-1]+1)*p; } printf("%.1lf\n",f[n]); return 0; }
luogu P1297 [国家集训队] 单选错位
-
破环为链,令 \(a_{n+1}=a_{1}\) 。
-
大力分讨。
- 当 \(a_{i}=a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i}}\) 。
- 当 \(a_{i}<a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i}} \times \frac{a_{i}}{a_{i+1}}=\frac{1}{a_{i+1}}\) 。
- 当 \(a_{i}>a_{i+1}\) 时,答对概率为 \(\frac{1}{a_{i+1}} \times \frac{a_{i+1}}{a_{i}}=\frac{1}{a_{i}}\) 。
-
归纳下,有 \(\sum\limits_{i=1}^{n}\dfrac{1}{\max(a_{i},a_{i+1})}\) 。
点击查看代码
ll a[10000010]; int main() { ll n,A,B,C,i; double ans=0; cin>>n>>A>>B>>C>>a[1]; for(i=2;i<=n;i++) { a[i]=(a[i-1]*A%100000001+B)%100000001; } for(i=1;i<=n;i++) { a[i]=a[i]%C+1; } a[n+1]=a[1]; for(i=1;i<=n;i++) { ans+=1.0/max(a[i],a[i+1]); } printf("%.3lf\n",ans); return 0; }
luogu P8804 [蓝桥杯 2022 国 B] 故障
-
套个贝叶斯公式即可。
-
\(P(A_{i}|B)=\dfrac{P(A_{i})P(B|A_{i})}{P(B)}=\dfrac{P(A_{i})P(B|A_{i})}{\sum\limits_{k=1}^{n}P(A_{k})P(B|A_{k})}\) 。
点击查看代码
int a[45],p[45][45],vis[45],f[45]; pair<double,int>ans[45]; bool cmp(pair<double,int> a,pair<double,int> b) { return ((a.first==b.first)?(a.second<b.second):a.first>b.first); } int main() { int n,m,q,x,i,j,k; double sum=0; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { cin>>p[i][j]; } } cin>>q; for(i=1;i<=q;i++) { cin>>x; vis[x]=1; } for(i=1;i<=n;i++) { ans[i].first=a[i]/100.0; ans[i].second=i; for(j=1;j<=m;j++) { ans[i].first*=(vis[j]==1)?p[i][j]/100.0:(100-p[i][j])/100.0; } sum+=ans[i].first; } sort(ans+1,ans+1+n,cmp); for(i=1;i<=n;i++) { printf("%d %.2lf\n",ans[i].second,ans[i].first/sum*100); } return 0; }
BZOJ1419 Red is good
-
类似 luogu P2719 搞笑世界杯 ,设 \(f_{i,j}\) 表示还剩 \(i\) 张红牌, \(j\) 张黑牌的期望得到钱数,状态转移方程为 \(\begin{cases} f_{i,j}=i & j=0 \\ f_{i,j}=\max(0,\frac{i}{i+j} \times (f_{i-1,j}+1)+\frac{j}{i+j} \times (f_{i,j-1}-1)) & j \ne 0 \end{cases}\) 。
-
最终,有 \(f_{r,b}\) 即为所求。
点击查看代码
double f[2][5010]; int main() { int r,b,i,j; cin>>r>>b; for(i=1;i<=r;i++) { f[i&1][0]=i; for(j=1;j<=b;j++) { f[i&1][j]=max(0.0,1.0*i/(i+j)*(f[(i-1)&1][j]+1)+1.0*j/(i+j)*(f[i&1][j-1]-1)); } } printf("%.6lf\n",floor(f[r&1][b]*1000000)/1000000); return 0; }
luogu P4206 [NOI2005] 聪聪与可可
-
题目问的应该是期望多少时间,而不是多少步。
-
设 \(f_{i,j}\) 表示聪聪在 \(i\) 点,可可在 \(j\) 点时的期望步数;设 \(nxt_{i,j}\) 表示聪聪在 \(i\) 点,可可在 \(j\) 点时的聪聪下一段时间去的地方。状态转移方程为 \(f_{i,j}=\frac{f_{nxt_{nxt_{i,j}},j}+1+\sum\limits_{(j,k) \in E}(f_{nxt_{nxt_{i,j}},k}+1)}{du_{j}+1}\) 。
-
\(nxt_{i,j}\) 可以通过求出最短路预处理出,接着记忆化搜索即可。
点击查看代码
struct node { int nxt,to; }e[2010]; int head[2010],dis[2010][2010],du[2010],nxt[2010][2010],cnt=0; double f[2010][2010]; bool vis[2010][2010]; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } double dfs(int x,int y) { if(vis[x][y]==false) { vis[x][y]=true; if(x==y)//因为同一个点的nxt是INF(仅限于我代码),所以不能用nxt判 { f[x][y]=0; } else { if(nxt[x][y]==y) { f[x][y]=1; } else { f[x][y]=(dfs(nxt[nxt[x][y]][y],y)+1.0)/(1.0*du[y]+1.0); for(int i=head[y];i!=0;i=e[i].nxt) { f[x][y]+=(dfs(nxt[nxt[x][y]][y],e[i].to)+1.0)/(1.0*du[y]+1.0); } } } } return f[x][y]; } int main() { int n,m,st,ed,u,v,i,j,k; cin>>n>>m>>st>>ed; memset(dis,0x3f,sizeof(dis)); memset(nxt,0x3f,sizeof(nxt)); for(i=1;i<=m;i++) { cin>>u>>v; add(u,v); add(v,u); dis[u][v]=dis[v][u]=1; du[u]++; du[v]++; } for(k=1;k<=n;k++) { for(i=1;i<=n;i++) { if(i!=k&&dis[i][k]!=0x3f3f3f3f) { for(j=1;j<=n;j++) { if(j!=k&&i!=j&&dis[k][j]!=0x3f3f3f3f) { dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); } } } } } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(dis[i][j]<=2) { nxt[i][j]=j; } else { for(k=head[i];k!=0;k=e[k].nxt) { if(dis[e[k].to][j]==dis[i][j]-1) { nxt[i][j]=min(nxt[i][j],e[k].to); } } } } } printf("%.3lf\n",dfs(st,ed)); return 0; }
CF148D Bag of mice
-
设 \(f_{i,j}\) 表示轮到公主抓时,袋子里还有 \(i\) 只白鼠, \(j\) 只黑鼠的概率。
-
大力分讨,画搜索树。
- 公主白鼠,概率为 \(\frac{i}{i+j}\) 。
- 公主黑鼠,龙白鼠,概率为 \(\frac{j}{i+j} \times \frac{i}{i+j-1}\) 。
- 公主黑鼠,龙黑鼠,跑出黑鼠,概率为 \(\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{j-2}{i+j-2}\) 。
- 公主黑鼠,龙黑鼠,跑出白鼠,概率为 \(\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{i}{i+j-2}\) 。
-
状态转移方程为 \(f_{i,j}=\frac{i}{i+j}+\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{j-2}{i+j-2} \times f_{i,j-3}+\frac{j}{i+j} \times \frac{j-1}{i+j-1} \times \frac{i}{i+j-2} \times f_{i-1,j-2}\) ,边界为 \(\begin{cases} f_{i,0}=1 & i \in [1,w] \\ f_{0,j}=0 & j \in [1,b] \end{cases}\) 。
-
最终,有 \(f_{w,b}\) 即为所求。
点击查看代码
double f[1010][1010]; int main() { int w,b,i,j; cin>>w>>b; for(i=1;i<=w;i++) { f[i][0]=1; for(j=1;j<=b;j++) { f[i][j]=1.0*i/(i+j); if(j-3>=0) { f[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*f[i][j-3]; } if(i-1>=0&&j>=2) { f[i][j]+=1.0*j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*f[i-1][j-2]; } } } printf("%.10lf\n",f[w][b]); return 0; }
CF768D Jon and Orbs
-
设 \(f_{i,j}\) 表示前 \(i\) 天取出了 \(j\) 种物品的概率,状态转移方程为 \(f_{i,j}=\frac{j}{n} \times f_{i-1,j}+\frac{n-j+1}{n} \times f_{i-1,j-1}\) ,边界为 \(f_{0,0}=1\) 。
-
预处理到 \(10000\) 就差不多了,详细需要调和级数,但我不会。
点击查看代码
double f[10010][1010]; int main() { int k,q,p,i,j; cin>>k>>q; f[0][0]=1; for(i=1;i<=10000;i++) { for(j=1;j<=k;j++) { f[i][j]=1.0*j/k*f[i-1][j]+1.0*(k-j+1)/k*f[i-1][j-1]; } } for(i=1;i<=q;i++) { cin>>p; for(j=1;j<=10000;j++) { if(f[j][k]>=p/2000.0) { cout<<j<<endl; break; } } } return 0; }
luogu P10672 【MX-S1-T1】壁垒
luogu P10673 【MX-S1-T2】催化剂
luogu P10668 BZOJ2720 [Violet 5] 列队春游
-
对题意的感性理解详见 BZOJ2720 列队春游 。
-
枚举第 \(i\) 个人,站在第 \(j\) 个位置,视野为 \(k(1 \le k \le j-1)\) 的概率为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l} \ge h_{i}]}{n-k}\) ,期望为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l} \ge h_{i}]}{n-k} \times k\) ;视野为 \(k=j\) 时的概率为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}}\) ,期望为 \(\dfrac{1}{n} \times \dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times k\) 。
- 可以通过 \(\dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k}}{A_{n-1}^{k}}=\dfrac{A_{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]}^{k-1}}{A_{n-1}^{k-1}} \times \dfrac{\sum\limits_{l=1}^{n}[h_{l}<h_{i}]-k+1}{n-k}\) 来递推求解。
点击查看代码
int h[310],high[310],slow[310]; int main() { int n,i,j,k; double ans=0,A; cin>>n; for(i=1;i<=n;i++) { cin>>h[i]; } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { if(i!=j) { if(h[i]>h[j]) { slow[i]++; } else { high[i]++; } } } } for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { A=1; for(k=1;k<=min(j-1,slow[i]+1);k++) { ans+=1.0/n*A*high[i]/(n-k)*k; A*=1.0*(slow[i]-k+1)/(n-k); } ans+=1.0/n*A*k; } } printf("%.2lf\n",ans); return 0; }
luogu P2982 [USACO10FEB] Slowing down G
-
单点修改。路径查询板子。
点击查看代码
struct node { int nxt,to; }e[200010]; int head[200010],c[200010],cc[200010],siz[200010],fa[200010],dep[200010],son[200010],top[200010],dfn[200010],cnt=0,tot=0; struct SMT { struct SegmentTree { int l,r,sum; }tree[800010]; int lson(int x) { return x*2; } int rson(int x) { return x*2+1; } void pushup(int rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; } void build(int rt,int l,int r) { tree[rt].l=l; tree[rt].r=r; if(l==r) { tree[rt].sum=cc[l]; return; } int mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void update(int rt,int pos,int val) { if(tree[rt].l==tree[rt].r) { tree[rt].sum+=val; return; } int mid=(tree[rt].l+tree[rt].r)/2; if(pos<=mid) { update(lson(rt),pos,val); } else { update(rson(rt),pos,val); } pushup(rt); } int query(int rt,int x,int y) { if(x<=tree[rt].l&&tree[rt].r<=y) { return tree[rt].sum; } int mid=(tree[rt].l+tree[rt].r)/2,ans=0; if(x<=mid) { ans+=query(lson(rt),x,y); } if(y>mid) { ans+=query(rson(rt),x,y); } return ans; } }T; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs1(int x,int father) { siz[x]=1; fa[x]=father; dep[x]=dep[father]+1; for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father) { dfs1(e[i].to,x); siz[x]+=siz[e[i].to]; son[x]=(siz[e[i].to]>siz[son[x]])?e[i].to:son[x]; } } } void dfs2(int x,int father,int id) { top[x]=id; tot++; dfn[x]=tot; cc[tot]=c[x]; if(son[x]!=0) { dfs2(son[x],x,id); for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=father&&e[i].to!=son[x]) { dfs2(e[i].to,x,e[i].to); } } } } void update1(int pos,int val) { T.update(1,dfn[pos],val); } int query1(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(dep[top[u]]>dep[top[v]]) { ans+=T.query(1,dfn[top[u]],dfn[u]); u=fa[top[u]]; } else { ans+=T.query(1,dfn[top[v]],dfn[v]); v=fa[top[v]]; } } if(dep[u]<dep[v]) { ans+=T.query(1,dfn[u],dfn[v]); } else { ans+=T.query(1,dfn[v],dfn[u]); } return ans; } int main() { int n,u,v,i; cin>>n; for(i=1;i<=n-1;i++) { cin>>u>>v; add(u,v); add(v,u); } dfs1(1,0); dfs2(1,0,1); T.build(1,1,n); for(i=1;i<=n;i++) { cin>>u; cout<<query1(1,u)<<endl; update1(u,1); } return 0; }
BZOJ2969 矩形粉刷
-
正难则反,考虑求不被小 M 粉刷过的格子个数的概率。
-
设 \(f_{i,j}\) 表示 \((i,j)\) 不被刷到 \(1\) 个随机矩形刷到的概率,状态转移方程为 \(f_{i,j}=(\frac{i-1}{w})^{2}+(\frac{w-i}{w})^{2}+(\frac{j-1}{h})^{2}+(\frac{h-j}{h})^{2}-(\frac{i-1}{w} \times \frac{j-1}{h})^{2}-(\frac{i-1}{w} \times \frac{h-j}{h})^{2}-(\frac{w-i}{w} \times \frac{j-1}{h})^{2}-(\frac{w-i}{w} \times \frac{h-j}{h})^{2}\) 。
- 建议画图,容斥一下,答案部分等于上面加下面加左面加右面减左上减右上减左下减右下。
-
最终,有 \(\sum\limits_{i=1}^{w}\sum\limits_{j=1}^{h}(1-f_{i,j}^{k})\) 即为所求。
点击查看代码
int main() { int k,w,h,i,j; double ans=0; cin>>k>>w>>h; for(i=1;i<=w;i++) { for(j=1;j<=h;j++) { ans+=1-pow(pow(1.0*(i-1)/w,2)+pow(1.0*(w-i)/w,2)+pow(1.0*(j-1)/h,2)+pow(1.0*(h-j)/h,2)-pow(1.0*(i-1)/w*1.0*(j-1)/h,2)-pow(1.0*(i-1)/w*1.0*(h-j)/h,2)-pow(1.0*(w-i)/w*1.0*(j-1)/h,2)-pow(1.0*(w-i)/w*1.0*(h-j)/h,2),k); } } printf("%.0lf\n",ans); return 0; }
SP1026 FAVDICE - Favorite Dice
-
设 \(f_{i}\) 表示当前已经掷了 \(i\) 种面,要掷完 \(n\) 种面的期望次数,有 \(\begin{cases} f_{i}=0 & i=n \\ f_{i}= \frac{i}{n} \times (f_{i}+1)+ \frac{n-i}{n} \times (f_{i+1}+1) & i \ne n \end{cases}\) ,移项得 \(\begin{cases} f_{i}=0 & i=n \\ f_{i}=f_{i+1}+ \frac{n}{n-i} & i \ne n \end{cases}\) 。
点击查看代码
double f[1010]; int main() { int t,n,i,j; cin>>t; for(i=1;i<=t;i++) { cin>>n; f[n]=0; for(j=n-1;j>=0;j--) { f[j]=f[j+1]+1.0*n/(n-j); } printf("%.2lf\n",f[0]); } return 0; }
luogu P2059 [JLOI2013] 卡牌游戏
-
感觉有点像 约瑟夫问题 ,考虑逆推。
-
由于牌是放回的,故剩下 \(i\) 个人的状态能继承剩下 \(i-1\) 个人的状态。
-
设 \(f_{i,j}\) 表示剩下 \(i\) 个人时,从庄主开始顺时针数第 \(j\) 个人胜出的概率,状态转移方程为 \(f_{i,j}=\sum\limits_{k=1}^{m}\frac{[(a_{k}-1) \bmod i+1 >j] \times f_{i-1,j+i-((a_{k}-1) \bmod i+1)}+[(a_{k}-1) \bmod i+1 <j] \times f_{i-1,j-((a_{k}-1) \bmod i+1)}}{m}\) ,边界为 \(f_{1,1}=1\) 。
点击查看代码
int a[110]; double f[110][110]; int main() { int n,m,i,j,k; cin>>n>>m; for(i=1;i<=m;i++) { cin>>a[i]; } f[1][1]=1; for(i=2;i<=n;i++) { for(j=1;j<=i;j++) { for(k=1;k<=m;k++) { if((a[k]-1)%i+1>j) { f[i][j]+=f[i-1][i+j-((a[k]-1)%i+1)]/(1.0*m); } if((a[k]-1)%i+1<j) { f[i][j]+=f[i-1][j-((a[k]-1)%i+1)]/(1.0*m); } } } } for(i=1;i<=n;i++) { printf("%.2lf",f[n][i]*100); cout<<"% "; } return 0; }
[ARC180A] ABA and BAB
-
两种操作等价于在一定条件下删除
AB
或BA
。 -
所有极长的
AB
或BA
的长度除以 \(2\) 向上取整后的结果即为所求。点击查看代码
const ll p=1000000007; char s[250010]; int main() { ll n,ans=1,len=0,i; scanf("%lld%s",&n,s+1); for(i=1;i<=n;i++) { if(s[i]!=s[i-1]) { len++; } else { ans=ans*((ll)ceil(1.0*len/2)%p)%p; len=1; } } ans=ans*((ll)ceil(1.0*len/2)%p)%p; cout<<ans<<endl; return 0; }
UVA11181 条件概率 Probability|Given
-
状压枚举计算即可。
点击查看代码
double p[50],f[50]; int main() { int n,r,cnt=0,i,j; double sum,num; while(cin>>n>>r) { if(n==0&&r==0) { break; } else { cnt++; sum=0; memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { cin>>p[i]; } for(i=0;i<=(1<<n)-1;i++) { if(__builtin_popcount(i)==r) { num=1; for(j=0;j<=n-1;j++) { num*=((i>>j)&1)?p[j+1]:1-p[j+1]; } for(j=0;j<=n-1;j++) { f[j+1]+=((i>>j)&1)*num; } sum+=num; } } cout<<"Case "<<cnt<<":"<<endl; for(i=1;i<=n;i++) { printf("%.6lf\n",f[i]/sum); } } } return 0; }
6.30
闲话
- 早上有体活,在宿舍颓。
- 上午 \(feifei\) 不顾我们概率期望还没写完的事实,非让我们开数位 \(DP\) ,称按照 POJ3208 Apocalypse Someday 和 luogu P4127 [AHOI2009] 同类分布 的做题情况来决定看不看视频。
- 高一的放假了,收拾行李,让明天自己去 HZ 。
- 下午 \(feifei\) 让我们先把概率期望没写的题跳了来写数位 \(DP\) ,还 \(D\) 了我们。
- 晚上 \(feifei\) 收手机的手法和寒假集训 \(miaomiao\) 手法一样,“还有没有要交的?再给你们一次机会”; \(feifei\) 把 @wang54321 认成了 @Pursuing_OIer ; \(feifei\) 说了下明天搬到 HZ 的“具体事项”——“明天早上不跑操,起床后直接把行李拉到机房楼下”。
做题纪要
CF280C Game on Tree
-
一个点被删掉当且仅当删掉了这个点或这个点的祖先节点之一,而其他节点并不影响删除。有点 \(x\) 被删掉的期望次数为 \(\dfrac{1}{dep_{x}}\) 。
-
最终,有 \(\sum\limits_{i=1}^{n}\dfrac{1}{dep_{i}}\) 即为所求。
点击查看代码
struct node { int nxt,to; }e[200010]; int head[200010],dep[200010],cnt=0; void add(int u,int v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void dfs(int x,int fa) { dep[x]=dep[fa]+1; for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa) { dfs(e[i].to,x); } } } int main() { int n,u,v,i; double ans=0; cin>>n; for(i=1;i<=n-1;i++) { cin>>u>>v; add(u,v); add(v,u); } dfs(1,0); for(i=1;i<=n;i++) { ans+=1.0/dep[i]; } printf("%.8lf\n",ans); return 0; }
luogu P2111 考场奇遇
-
设 \(f_{i,j}\) 表示做到第 \(i\) 道题时,对了 \(j\) 道题的概率。状态转移方程为 \(f_{i,j}= \begin{cases} f_{i-1,j-1} \times A \%+f_{i-1,j} \times (1-A \%) & s_{i}=1 \\ f_{i-1,j} \times A \%+f_{i-1,j-1} \times (1-A \%) & s_{i}=0 \end{cases}\)
-
最终,有 \(\sum\limits_{i=q}^{n}f_{n,i}\) 即为所求。
点击查看代码
double f[2][10010]; int main() { int n,q,i,j; double a,ans=0; char s; cin>>n>>a>>q; a/=100; f[0][0]=1; for(i=1;i<=n;i++) { cin>>s; if(s=='1') { f[i&1][0]=f[(i-1)&1][0]*(1.0-a); } else { f[i&1][0]=f[(i-1)&1][0]*a; } for(j=1;j<=i;j++) { if(s=='1') { f[i&1][j]=f[(i-1)&1][j-1]*a+f[(i-1)&1][j]*(1.0-a); } else { f[i&1][j]=f[(i-1)&1][j]*a+f[(i-1)&1][j-1]*(1.0-a); } } } for(i=q;i<=n;i++) { ans+=f[n&1][i]; } printf("%.3lf\n",ans); return 0; }
luogu P1850 [NOIP2016 提高组] 换教室
-
因变量重名,以下所称的 \(\{ p \}\) 指题面中的 \(\{ k \}\) 。
-
设 \(f_{i,j,0/1}\) 表示第 \(i\) 个时间段成功换了 \(j\) 个教室,当前不申请换/申请换教室的耗费的体力值的总和的最小期望,状态转移方程为 \(\begin{cases} f_{i,j,0}=\min \begin{cases} f_{i-1,j,0}+dis_{c_{i-1},c_{i}} \\ f_{i-1,j,1}+(1-p_{i-1}) \times dis_{c_{i-1},c_{i}}+p_{i-1} \times dis_{d_{i-1},c_{i}} \end{cases} \\ f_{i,j,1}=\min \begin{cases} f_{i-1,j-1,0}+(1-p_{i}) \times dis_{c_{i-1},c_{i}}+p_{i} \times dis_{c_{i-1},d_{i}} \\ f_{i-1,j-1,1}+(1-p_{i-1})(1-p_{i}) \times dis_{c_{i-1},c_{i}}+p_{i-1}p_{i} \times dis_{d_{i-1},d_{i}}+(1-p_{i-1})p_{i} \times dis_{c_{i-1},d_{i}}+p_{i-1}(1-p_{i}) \times dis_{d_{i-1},c_{i}} \end{cases} \end{cases}\) ,边界为 \(f_{1,0,0}=f_{1,1,1}=0\) 。
-
最终,有 \(\min\limits_{i=0}^{m} \{ f_{n,i,1},f_{n,i,0} \}\) 即为所求。
点击查看代码
int dis[2010][2010],c[2010],d[2010]; double p[2010],f[2010][2010][2]; int main() { int n,m,v,e,x,y,z,i,j,k; double ans=0x3f3f3f3f; cin>>n>>m>>v>>e; memset(dis,0x3f,sizeof(dis)); for(i=1;i<=n;i++) { cin>>c[i]; } for(i=1;i<=n;i++) { cin>>d[i]; } for(i=1;i<=n;i++) { cin>>p[i]; } for(i=1;i<=v;i++) { dis[i][i]=0; } for(i=1;i<=e;i++) { cin>>x>>y>>z; dis[x][y]=min(dis[x][y],z); dis[y][x]=min(dis[y][x],z); } for(k=1;k<=v;k++) { for(i=1;i<=v;i++) { for(j=1;j<=v;j++) { dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); } } } for(i=1;i<=n;i++) { for(j=0;j<=m;j++) { f[i][j][0]=f[i][j][1]=0x3f3f3f3f; } } f[1][0][0]=f[1][1][1]=0; for(i=2;i<=n;i++) { for(j=0;j<=min(i,m);j++) { f[i][j][0]=min(f[i-1][j][0]+dis[c[i-1]][c[i]],f[i-1][j][1]+(1-p[i-1])*dis[c[i-1]][c[i]]+p[i-1]*dis[d[i-1]][c[i]]); if(j-1>=0) { f[i][j][1]=min(f[i-1][j-1][0]+(1-p[i])*dis[c[i-1]][c[i]]+p[i]*dis[c[i-1]][d[i]],f[i-1][j-1][1]+(1-p[i-1])*(1-p[i])*dis[c[i-1]][c[i]]+p[i-1]*p[i]*dis[d[i-1]][d[i]]+(1-p[i-1])*p[i]*dis[c[i-1]][d[i]]+p[i-1]*(1-p[i])*dis[d[i-1]][c[i]]); } } } for(i=0;i<=m;i++) { ans=min(ans,min(f[n][i][0],f[n][i][1])); } printf("%.2lf\n",ans); return 0; }
luogu P2473 [SCOI2008] 奖励关
-
设 \(f_{i,s}\) 表示 \(1 \sim i-1\) 次获取宝物的状态为 \(s\) 时, \(i \sim k\) 次的最大期望得分。状态转移方程为 \(f_{i,s}=\sum\limits_{j=1}^{n}\frac{[S_{j} \in s] \times \max(f_{i+1,s},f_{i+1,s|(1<<(j-1))}+p_{j})+[S_{j} \notin s] \times f_{i+1,s}}{n}\)
-
最终,有 \(f_{1,0}\) 即为所求。
点击查看代码
int p[103],vis[103]; double f[103][(1<<16)+10]; int main() { int k,n,x,i,s,j; cin>>k>>n; for(i=1;i<=n;i++) { cin>>p[i]; while(cin>>x) { if(x==0) { break; } else { vis[i]|=(1<<(x-1)); } } } for(i=k;i>=1;i--) { for(s=0;s<=(1<<n)-1;s++) { for(j=1;j<=n;j++) { f[i][s]+=1.0*(((s&vis[j])==vis[j])?max(f[i+1][s],f[i+1][s|(1<<(j-1))]+p[j]):f[i+1][s])/n; } } } printf("%.6lf\n",f[1][0]); return 0; }
luogu P4284 [SHOI2014] 概率充电器
-
\(P(A \bigcup B)=P(A)+P(B)-P(A \bigcap B)=P(A)+P(B)-P(A) \times P(B)\)
-
在第一遍 \(DFS\) 中,设 \(f_{x}\) 表示 \(x\) 充电的概率,初始值为 \(q_{x} \%\) ,每增加一棵子树,均有 \(f_{x}=f_{x}+f_{y} \times p_{x,y}\%-f_{x} \times f_{y} \times p_{x,y}\%\) 。
-
在第二遍 \(DFS\) 中,同理,设 \(f_{fa_{x}}=k+f_{x} \times p_{fa_{x},x}\%-k \times f_{x} \times p_{fa_{x},x}\%\) ,解得 \(k=\frac{f_{fa_{x}}-f_{x} \times p_{fa_{x},x}\%}{1-f_{x} \times p_{fa_{x},x}\%}\) ,此时有 \(f_{x}=f_{x}+k \times p_{fa_{x},x}\%-f_{x} \times k \times p_{fa_{x},x}\%\) ,特别地,当 \(1-f_{x} \times p_{fa_{x},x}\%=0\) 时规定 \(k=0\) 。
- 类似换根过程中的删除影响。
-
最终,有 \(\sum\limits_{i=1}^{n}f_{i}\) 即为所求。
点击查看代码
const double eps=1e-10; struct node { int nxt,to; double p; }e[1000010]; int head[1000010],cnt=0; double q[1000010],f[1000010]; void add(int u,int v,double p) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; e[cnt].p=p; head[u]=cnt; } void dfs(int x,int fa) { f[x]=q[x]; for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa) { dfs(e[i].to,x); f[x]+=f[e[i].to]*e[i].p-f[x]*f[e[i].to]*e[i].p; } } } void reroot(int x,int fa) { for(int i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa) { if(1-f[e[i].to]*e[i].p>eps) { double k=(f[x]-f[e[i].to]*e[i].p)/(1-f[e[i].to]*e[i].p); f[e[i].to]+=k*e[i].p-f[e[i].to]*k*e[i].p; } reroot(e[i].to,x); } } } int main() { int n,u,v,p,i; double ans=0; cin>>n; for(i=1;i<=n-1;i++) { cin>>u>>v>>p; add(u,v,p/100.0); add(v,u,p/100.0); } for(i=1;i<=n;i++) { cin>>q[i]; q[i]/=100.0; } dfs(1,0); reroot(1,0); for(i=1;i<=n;i++) { ans+=f[i]; } printf("%.6lf\n",ans); return 0; }
luogu P3232 [HNOI2013] 游走
-
设 \(f_{i}\) 表示 \(i\) 号顶点的期望经过次数,状态转移方程为 \(f_{i}=[i=1 \lor i=n]+[i \ne n] \times [j \ne n] \times \sum\limits_{(i,j) \in E}\frac{f_{j}}{du_{j}}=[i=1 \lor i=n]+\sum\limits_{i=1}^{n}\frac{[i \ne n] \times [j \ne n] \times [(i,j) \in E] \times f_{j}}{du_{j}}\) 。
-
类似 luogu P2973 [USACO10HOL] Driving Out the Piggies G ,移项得到方程组 \(\begin{cases} f_{1}-\sum\limits_{i=1}^{n}\frac{[j \ne n] \times [(1,j) \in E]}{du_{j}} \times f_{j}=1 \\ f_{i}-\sum\limits_{i=1}^{n}\frac{[j \ne n] \times [(i,j) \in E]}{du_{j}} \times f_{j}=0 & 1<i<n \\ f_{n}=1 \end{cases}\) ,高斯消元解一下。
-
设 \(g_{i}\) 表示第 \(i\) 条边的期望经过次数,状态转移方程为 \(g_{i}=[u_{i} \ne n] \times \frac{f_{u_{i}}}{du_{u_{i}}}+[v_{i} \ne n] \times \frac{f_{v_{i}}}{du_{v_{i}}}\) 。
-
由排序不等式,期望经过次数越多的边标号越小。最终,将 \(g\) 升序排序后有 \(\sum\limits_{i=1}^{m}g_{i}(m-i+1)\) 即为所求。
点击查看代码
const double eps=1e-12; int du[510],dis[510][510],u[125010],v[125010]; double a[510][510],f[510],g[125010]; int main() { int n,m,val,i,j,k; double ans=0; cin>>n>>m; for(i=1;i<=m;i++) { cin>>u[i]>>v[i]; dis[u[i]][v[i]]=dis[v[i]][u[i]]=1; du[u[i]]++; du[v[i]]++; } for(i=1;i<=n;i++) { a[i][i]=1; for(j=1;j<=n;j++) { if(j!=i) { a[i][j]=-1.0*(i!=n)*(j!=n)*(dis[i][j]==1)/du[j]; } } a[i][n+1]=(i==1||i==n); } for(i=1;i<=n;i++) { val=i; for(j=i;j<=n;j++) { if(fabs(a[j][i])-fabs(a[val][i])>eps) { val=j; } } for(j=1;j<=n+1;j++) { swap(a[i][j],a[val][j]); } if(a[i][i]!=0) { for(j=1;j<=n;j++) { if(j!=i) { for(k=i+1;k<=n+1;k++) { a[j][k]-=a[i][k]*a[j][i]/a[i][i]; } } } } } for(i=1;i<=n;i++) { f[i]=a[i][n+1]/a[i][i]; } for(i=1;i<=m;i++) { g[i]=(u[i]!=n)*f[u[i]]/(1.0*du[u[i]])+(v[i]!=n)*f[v[i]]/(1.0*du[v[i]]); } sort(g+1,g+1+m); for(i=1;i<=m;i++) { ans+=g[i]*(m-i+1); } printf("%.3lf\n",ans); return 0; }
北京建筑大学2024年程序设计竞赛(同步赛) F 买蛋糕
-
条件语句。
点击查看代码
int main() { int n,a,b,c,sum=0,i; cin>>n; for(i=1;i<=n;i++) { cin>>a>>b>>c; sum+=(a+b+c>=100); } cout<<sum<<endl; return 0; }
北京建筑大学2024年程序设计竞赛(同步赛) G 区间翻转
-
只关注元素 \(1\) 所处的位置即可。
点击查看代码
int main() { int n,k,m,l,r,i,j; cin>>n>>k>>m; for(i=1;i<=m;i++) { cin>>l>>r; if(l<=k&&k<=r) { k=r-(k-l); } } cout<<k<<endl; return 0; }
北京建筑大学2024年程序设计竞赛(同步赛) I 洗牌
-
模拟。
点击查看代码
int a[100],b[100]; int main() { int n,l,r,i,j,k; cin>>n; for(i=1;i<=54;i++) { a[i]=i; } for(i=1;i<=n;i++) { cin>>l>>r; for(j=1;j<=r;j++) { b[j]=a[j]; } for(j=1,k=l;k<=r;j++,k++) { a[j]=b[k]; } for(j=r-l+2,k=1;k<=l-1;j++,k++) { a[j]=b[k]; } } for(i=1;i<=54;i++) { cout<<a[i]<<" "; } return 0; }
北京建筑大学2024年程序设计竞赛(同步赛) A 寿命修改
-
最多只会死亡 \(n\) 只青蛙,对于死亡的青蛙线段树上暴力找然后单点修改即可,否则同正常的线段树区间修改。
点击查看代码
ll a[200010]; struct SMT { struct SegmentTree { ll l,r,sum,lazy,minn,len; }tree[800010]; ll lson(ll x) { return x*2; } ll rson(ll x) { return x*2+1; } void pushup(ll rt) { tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); tree[rt].len=tree[lson(rt)].len+tree[rson(rt)].len; } void build(ll rt,ll l,ll r) { tree[rt].l=l; tree[rt].r=r; tree[rt].lazy=0; if(l==r) { tree[rt].sum=tree[rt].minn=a[l]; tree[rt].len=1; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void pushdown(ll rt) { if(tree[rt].lazy!=0) { tree[lson(rt)].lazy+=tree[rt].lazy; tree[rson(rt)].lazy+=tree[rt].lazy; tree[lson(rt)].sum+=tree[rt].lazy*tree[lson(rt)].len; tree[rson(rt)].sum+=tree[rt].lazy*tree[rson(rt)].len; tree[lson(rt)].minn+=tree[rt].lazy; tree[rson(rt)].minn+=tree[rt].lazy; tree[rt].lazy=0; } } void update(ll rt,ll x,ll y,ll val) { if(tree[rt].len==0) { return; } if(tree[rt].l==tree[rt].r) { tree[rt].sum+=val; tree[rt].minn+=val; if(tree[rt].minn<=0) { tree[rt].sum=tree[rt].lazy=0; tree[rt].minn=0x3f3f3f3f; tree[rt].len=0; } return; } if(x<=tree[rt].l&&tree[rt].r<=y) { if(tree[rt].minn+val>0) { tree[rt].lazy+=val; tree[rt].sum+=val*tree[rt].len; tree[rt].minn+=val; return; } } pushdown(rt); ll mid=(tree[rt].l+tree[rt].r)/2; if(x<=mid) { update(lson(rt),x,y,val); } if(y>mid) { update(rson(rt),x,y,val); } pushup(rt); } ll query(ll rt,ll x,ll y) { if(x<=tree[rt].l&&tree[rt].r<=y) { return tree[rt].sum; } pushdown(rt); ll mid=(tree[rt].l+tree[rt].r)/2,ans=0; if(x<=mid) { ans+=query(lson(rt),x,y); } if(y>mid) { ans+=query(rson(rt),x,y); } return ans; } }T; int main() { ll n,m,pd,l,r,x,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } T.build(1,1,n); for(i=1;i<=m;i++) { cin>>pd>>l>>r; if(pd==1) { cin>>x; T.update(1,l,r,x); } else { cout<<T.query(1,l,r)<<endl; } } return 0; }
牛客 NC275421 嘤嘤不想做计几喵
牛客 NC275501 嘤嘤不想打怪兽喵
牛客 NC275503 嘤嘤不想买东西喵
牛客 NC275631 嘤嘤不想求异或喵
牛客 NC275518 嘤嘤不想解方程喵
[ABC360A] A Healthy Breakfast
-
模拟。
点击查看代码
int vis[200]; char s[4]; int main() { for(int i=1;i<=3;i++) { cin>>s[i]; vis[s[i]]=i; } if(vis['R']<vis['M']) { cout<<"Yes"<<endl; } else { cout<<"No"<<endl; } return 0; }
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18272102,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。