Codeforces Round #301 (Div. 2)

A - Combination Lock

题意:

给两个密码,为最小多少次能吻合。

思路:

对于每一位设a<b,sum+=min(b-a,10+a-b)

#include <bits/stdc++.h>
using namespace std;
int main()
{
   int n;
   char x[1234],y[1234];
   while(cin>>n)
   {
       scanf("%s%s",x,y);
       int ans=0;
       for(int i=0;i<n;i++)
       {
           int a=x[i]-'0';
           int b=y[i]-'0';
           if(a>b) swap (a,b);
           ans+=min(b-a,10+a-b);
       }
       printf("%d\n",ans);
   }
    return 0;
}

B - School Marks

题意:

给n,k,p,x,y,代表总共有n个数,已知有k个数,这些数的最大值不能超过p,数的总和不能超过x,排序完的中位数大于等于y

问剩下的n-k个数是什么,输出任意答案。

思路:

先统计k个数中小于y的数有cnt个,cnt不能大于n/2,顺便求和。

接着放n/2-cnt个1,这里要注意有可能中位数就是1,那么顺便计算一下放了多少个数,放满n个了也要停。

接着剩下的放y,判断和是否会超过。

代码:

#include <bits/stdc++.h>
using namespace std;
int v[1234];
int main()
{
    int n,k,p,x,y;
    while(cin>>n>>k>>p>>x>>y)
    {
        int sum=0,cnt=0,kx=0;
        for(int i=0;i<k;i++)
        {
            int x;
            scanf("%d",&x);
            if(x<y) cnt++;
            sum+=x;
        }
        if(cnt>n/2)
        {
            puts("-1");
            continue;
        }
        for(int i=cnt;i<n/2 && k<n;i++)  //k<n 防止中位数正好是1
        {
            k++;
            sum++;
            v[kx++]=1;
        }
        for(int i=k;i<n;i++)
        {
            sum+=y;
            v[kx++]=y;
        }
        if(sum>x) printf("-1\n");
        else for(int i=0;i<kx;i++) printf(i==kx-1?"%d\n":"%d ",v[i]);
    }
    return 0;
}

C - Ice Cave

题意:

给n*m的矩阵有‘.’和'X',点代表冰面,X代表洞。冰面走过后就变成洞。

然后给起点和终点,问能否从起点走到终点,正好掉进终点的洞里,除了终点的洞其他洞不能再走。

思路:

很考验脑洞的一道题,因为判断可达,所以可以直接dfs判断,比bfs来的快并且简单。

只要考虑一个点是否被走了2次就好了,根据dfs的特性直接就是答案了。

代码:

#include <bits/stdc++.h>
using namespace std;
int v[1234];
char mp[555][555];
int used[555][555];
int dis[4][2]= {{0,1},{0,-1},{-1,0},{1,0}};
int f,sx,sy,ex,ey,n,m;
void dfs(int x,int y)
{
    if(f) return;
    if(x<0 || x>=n || y<0 || y>=m ) return ;
    if(x==ex && y==ey && used[x][y]>=2)
    {
        f=1;
        return ;
    }
    if(used[x][y]>=2) return ;
    used[x][y]++;
    for(int i=0; i<4; i++)
    {
        int xx=x+dis[i][0];
        int yy=y+dis[i][1];
        dfs(xx,yy);
        if(f) return;
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=-1)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%s",mp[i]);
            for(int j=0; j<m; j++)
            {
                if(mp[i][j]=='.') used[i][j]=1;
                else used[i][j]=2;
            }
        }
        cin>>sx>>sy>>ex>>ey;
        sx--;
        sy--;
        ex--;
        ey--;
        f=0;
        used[sx][sy]=1;
        dfs(sx,sy);
        puts(f==1?"YES":"NO");
    }
    return 0;
}

D - Bad Luck Island

题意:

一个岛上有3个物种石头、剪刀、布,各a、b、c个。

每次随机两个东西碰面,相克的话被克的死掉,否则平安无事。

分别求三个物种只有这个物种剩下来的概率。

思路:

一个概率dp,设dp[i][j][k]为当前有i个石头,j个剪刀,k个布,石头留下的概率。

那么对于每个状态来说,都只会发生两种事情,就是某个物种少1或者大家平安。

所以 dp[i][j][k]=(i*j)/(sum*(sum-1)/2)*dp[i][j-1][k]+(j*k)/(sum*(sum-1)/2)

*dp[i][j][k-1]+(k*i)/(sum*(sum-1)/2)*dp[i-1][j][k]+(C(i,2)+C(j,2)+C(k,2))/(sum*(sum-1)/2)*dp[i][j][k]

然后移项求解一下就好了。

用的是记忆化搜索,然后考虑一下边界就好了。

对于石头赢的话就是。

    if(!i) return 0.0;
    if(!j) return 1.0;
    if(!k) return 0.0;
然后因为太弱了,所以算三遍分别求出每个种类赢的概率。

代码:

#include <bits/stdc++.h>
#define eps 1e-10
using namespace std;
double dp1[101][101][101];
double dfs1(int a,int b,int c)  //石头
{
    if(!a) return 0.0;
    if(!c) return 1.0;
    if(!b) return 0.0;
    if(fabs(dp1[a][b][c]+1)>eps) return dp1[a][b][c];
    double ans=0.0;
    double cnt=a+b+c;
    cnt=(cnt*(cnt-1.0))/2;
    double bs=0.0;
    if(a>=2) bs+=(1.0*a*(a-1.0))/2;
    if(b>=2) bs+=(1.0*b*(b-1.0))/2;
    if(c>=2) bs+=(1.0*c*(c-1.0))/2;
    bs=bs/cnt;
    bs=1.0-bs;
    ans+=(a*c)/cnt*dfs1(a-1,b,c);
    ans+=(c*b)/cnt*dfs1(a,b,c-1);
    ans+=(b*a)/cnt*dfs1(a,b-1,c);
    ans=ans/bs;
    return dp1[a][b][c]=ans;
}
double dp2[101][101][101];
double dfs2(int a,int b,int c) //剪刀
{
    if(!b) return 0.0;
    if(!a) return 1.0;
    if(!c) return 0.0;
    if(fabs(dp2[a][b][c]+1)>eps) return dp2[a][b][c];
    double ans=0.0;
    double cnt=a+b+c;
    cnt=(cnt*(cnt-1.0))/2;
    double bs=0.0;
    if(a>=2) bs+=(1.0*a*(a-1.0))/2;
    if(b>=2) bs+=(1.0*b*(b-1.0))/2;
    if(c>=2) bs+=(1.0*c*(c-1.0))/2;
    bs=bs/cnt;
    bs=1.0-bs;
    ans+=(a*c)/cnt*dfs2(a-1,b,c);
    ans+=(c*b)/cnt*dfs2(a,b,c-1);
    ans+=(b*a)/cnt*dfs2(a,b-1,c);
    ans=ans/bs;
    return dp2[a][b][c]=ans;
}
double dp3[101][101][101];
double dfs3(int a,int b,int c) //布
{
    if(!c) return 0.0;
    if(!b) return 1.0;
    if(!a) return 0.0;
    if(fabs(dp3[a][b][c]+1)>eps) return dp3[a][b][c];
    double ans=0.0;
    double cnt=a+b+c;
    cnt=(cnt*(cnt-1.0))/2;
    double bs=0.0;
    if(a>=2) bs+=(1.0*a*(a-1.0))/2;
    if(b>=2) bs+=(1.0*b*(b-1.0))/2;
    if(c>=2) bs+=(1.0*c*(c-1.0))/2;
    bs=bs/cnt;
    bs=1.0-bs;
    ans+=(a*c)/cnt*dfs3(a-1,b,c);
    ans+=(c*b)/cnt*dfs3(a,b,c-1);
    ans+=(b*a)/cnt*dfs3(a,b-1,c);
    ans=ans/bs;
    return dp3[a][b][c]=ans;
}
int main()
{
    int a,b,c;
    memset(dp1,-1,sizeof(dp1));
    memset(dp2,-1,sizeof(dp2));
    memset(dp3,-1,sizeof(dp3));
    while(cin>>a>>b>>c)
    {
        printf("%.10f %.10f %.10f\n",dfs1(a,b,c),dfs2(a,b,c),dfs3(a,b,c));
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值