220430学习记录:简单模拟,概率dp,二分问题

学了概率dp,可能练了二分

1.CodeForces - 148D Bag of mice

Problem - 148D - Codeforces

题目:公主(先手)和龙抓老鼠 ,有黑鼠b只,白鼠w只,只有公主抓到白鼠才算公主赢。龙每抓走一只老鼠,有另一只老鼠跳出袋子,求公主赢的概率。

设dp[i][j](i是剩下i只白鼠,j是剩下黑鼠)

最后结束的情况:

1.公主拿到了白鼠:dp[i][j]=i/(i+j);

2.龙拿到白鼠,公主赢概率为0;

过程情况:

1.公主(黑)和龙(黑)拿完后,跳出黑鼠:dp[i][j]+=dp[i][j-3]* j/(i+j) * (j-1)/(i+j-1) * (j-2)/(i+j-2);

2.公主(黑)和龙(黑)拿完后,跳出白鼠:dp[i][j]+=dp[i][j-2]* j/(i+j) * (j-1)/(i+j-1) * i/(i+j-2);

dp[i][j]表示的是在经历这些过程后,公主赢的概率。

初始化:要分别初始化0只白鼠和0只黑鼠的情况;

如果不初始化直接循环的话/(i+j-2)的部分会报错。另外注意输出的是f【w】【b】,不要反了。

代码:

#include<bits/stdc++.h>
using namespace std;
double f[1003][1003];//bai hei
//bai win
int main()
{
    int w,b;cin>>w>>b;
    for(int i=0;i<=w;i++)f[i][0]=1.0;
    for(int i=0;i<=b;i++)f[0][i]=0.0;
      for(int i=1;i<=w;i++){
            for(int j=1;j<=b;j++){
                f[i][j]=1.0*i/(i+j);//win
                if(j>=3)//three black
                f[i][j]+=1.0*j/(i+j)*1.0*(j-1)/(i+j-1)*(j-2)/(i+j-2)*1.0*f[i][j-3];
                if(j>=2)//two black one white
                f[i][j]+=1.0*j/(i+j)*1.0*(j-1)/(i+j-1)*i/(i+j-2)*1.0*f[i-1][j-2];
            }
      }
      cout<<fixed<<setprecision(9)<<f[w][b];
    return 0;
}

2.poj2096 Collecting Bugs  

2096 -- Collecting Bugs (poj.org)

 参考题解:【POJ 2096】Collecting Bugs 概率期望dp

题目:一共要n个A和s个B,一天你能找到一个东西(属于A属于B),它可能属于你找到过的A也可能属于你没找过的A,B同。问找到所有n个A和s个B的期望天数。

思路:计算期望E=∑所有可能需要的天数*概率

简单画个示意图来说,如下图所示:

问A到D的期望时间,所以E(A)=1+p1*E(B)+p2*E(C);

设f[i][j]是已经找到了i个A和j个B所花的天数;

f[i][j]=p1*f[i][j]+p2*f[i][j+1]+p2*f[i][j+1]+p3*f[i+1][j]+p4*f[i+1][j+1]+1;

其中,p1=(i*j)/(n*s),p2=(i/n)*(1-j/s),p3=(1-i/n)*(j/s),p4=(1-i/n)*(1-j/s);

所以移一下项,通一下分,得出:

f[i][j]=(1.0*(n-i)*j*f[i+1][j]+1.0*(s-j)*i*f[i][j+1]+1.0*(s-j)*(n-i)*f[i+1][j+1]+s*n)/(1.0*s*n-i*j);

代码: 

#include<iostream>
#include <iomanip>
using namespace std;
double f[1003][1003];
int main()
{
    int n,s;cin>>n>>s;
    for(int i=n;i>=0;i--)
    for(int j=s;j>=0;j--){
        if(i==n&&j==s)continue;
        f[i][j]=(1.0*(n-i)*j*f[i+1][j]+
                 1.0*(s-j)*i*f[i][j+1]+
                 1.0*(s-j)*(n-i)*f[i+1][j+1]+s*n)
                 /(1.0*s*n-i*j);
    }
    cout<<fixed<<setprecision(9)<<f[0][0];
    return 0;
}

3.Educational Codeforces Round 118 C. Poisoned Dagger 

Problem - C - Codeforces

题目:勇士要带毒药杀巨龙,毒药持续时间K秒;输入攻击时间,每次攻击会更新毒药持续时间;在能杀死血条为H的巨龙的条件下,问K的最小值。

用二分法+模拟。

二分的模板为:(下面是左闭右开的情况)

二分查找:

mid=l+(r-l)/2;

[0,n)--------while left<right;left = mid+1;right=mid;

[0,n-1]--------while left<=right;left = mid+1;right=mid-1;

二分问题:

mid=l+(r-l+1)/2;if(test(mid)) l=mid;else r=mid-1;

mid=(l+r)/2;if(test(mid)) r=mid;else l=mid+1;

代码:

#include<bits/stdc++.h>
using namespace std;
long long a[101];long long n,h;
bool check(long long mid){
    long long ti=h;
    for(int i=1;i<n;i++){
        if(a[i+1]-a[i]<=mid) ti=ti-(a[i+1]-a[i]);
        else ti=ti-mid;
        if(ti<=0)return 1;
    }
    ti=ti-mid;
    if(ti<=0)return 1;
    return 0;
}
int main()
{
    int T;cin>>T;
    while(T--){
        cin>>n>>h;
        for(int i=1;i<=n;i++) cin>>a[i];
        long long l=0,r=1e18+1,mid;
		while(r>l){
			mid=(r+l)/2;
			if(check(mid)) r=mid;
			else l=mid+1;
		}
		cout<<r<<endl;
    }
    return 0;
}

4.Codeforces1623C Balanced Stone Heaps

Problem - C - Codeforces

题目: 第i堆石头取出3d个石头,往前两堆石头i-1放d个石头,i-2放2d个石头,问最少的石头的堆最多有多少石头。

思路就是模拟,每个堆卡在mid这个线上,同时前两个堆要在mid的线上,这样子check返回真。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,h[200005],b[200005];
bool check(int mid){
    for(int i=1;i<=n;i++)b[i]=h[i];
    for(int i=n;i>=3;i--){
        if(b[i]<mid)return 0;
        if(b[i]>=mid){
            int d=min((b[i]-mid)/3,h[i]/3);
            b[i-1]+=d;b[i-2]+=2*d;
        }
    }
    return b[1]>=mid&&b[2]>=mid;

}
signed main()
{
    int T;cin>>T;
    while(T--){
        cin>>n;int maxx=0;
        for(int i=1;i<=n;i++){cin>>h[i];maxx=max(maxx,h[i]);}
        int l=0,r=maxx+1,mid,ans;
        while(l<r){
        mid=l+(r-l+1)/2;
        if(check(mid)){l=mid;}
        else r=mid-1;
        }
        cout<<l<<endl;
    }
    return 0;
}

5. 牛客练习赛98 AIR Triplet

C-AIR Triplet_牛客练习赛98 (nowcoder.com)

ai⊕aj=0,aj⊕ak=0:这意味着ai=aj=ak!!!

6. 牛客练习赛50tokitsukaze and Connection 

 tokitsukaze and Connection (nowcoder.com)

我用vector记录26个字母的下标判断是否连续,但其他人有更简单的做法。

#include<bits/stdc++.h>
using namespace std;
int vis[100];
int main()
{
	int n;
	string s;
	cin>>n>>s;
	for(int i=1;i<n;i++){
		if(s[i-1]==s[i])continue;
		else{
			vis[s[i-1]]=1;
			if(vis[s[i]]==1){printf("NO\n");return 0;}
		}
	}
	printf("YES\n");
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值