备战 清华大学 上机编程考试-冲刺前50%,倒数第4天

T1:四操作

有一个n个元素的数列,元素的值只能是0 1 2三个数中的一个,定义四种操作,(1 i x)表示为把第i位替换成x,x也只能是0 1 2三个数中的一个,(2 i j)表示把第i个数到第j个数所有的元素值加1,并对3取模,(3 i j)表示把第i个数到第j个数之间的序列的颠倒顺序,(4 i j)表示查询第i个数到第j个数之间的序列是否存在三个或以上相同数,如果有,输出yes,否则输出no

输入:第一行输入n,接下来一行输入n个数,保证是0 1 2中的一个,第三行输入一个数q,表示操作个数,接下来q行输入q种操作 输出:每次第四次操作时,输出yes或者no 数据范围:不记得了

解:

模拟题:选择好数据结构——进行模拟操作:

//四种操作:
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<string>
//n个元素的数列, 每个元素是 0/1/2
//总共如下4种操作:
//(1) "1 i x"——把第i个改成x
//(2) "2 i j"——把vec[i]-vec[j]统统+1 %3
//(3) "3 i j"——把vec[i]-vec[j]之间逆序
//(4) "4 i j"——查询vec[i]-vec[j]之间是否存在相同的3个以上数
//第4种中,如果 j-i+1 >=9,直接输出yes
using namespace std;

void swap(int & a,int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

int main()
{
    //方法一:直接模拟 - 模拟法最重要的是,如何选择存储数据的结构
    //暴力:直接用vector
    int n ;
    cin>>n;
    vector<int> vec(n+1,0);  //干脆假设i,j下标都是从1开始
    for(int i = 1;i<=n;i++)
    {
        cin>>vec[i];
    }
    int q;
    cin>>q;
    while(q--)
    {
        int num1,num2,num3;
        cin>>num1>>num2>>num3;
        if(num1 == 1)
        {
            vec[num2] = num3;
        }
        else if(num1 == 2)
        {   
            for(int i = num2; i<=num3 ;i++)
            {
                vec[i] = (vec[i]+1)%3;
            }

        }
        else if(num1 == 3)
        {
            int i = num2;
            int j = num3;
            while(j > i)
            {
                swap(vec[i],vec[j]);
                i++;j--;
            }
        }
        else if (num1 == 4)
        {
            if(num3 - num2 + 1 >= 9)
            {
                cout<<"yes"<<endl;
            }
            else
            {
                int flag = 0;
                int a[3] = {0};
                for(int i = num2;i<=num3;i++)
                {
                    a[vec[i]]++;
                    if(a[vec[i]] >=3)
                    {
                        cout<<"yes"<<endl;
                        flag = 1;
                        break;
                    }
                }
                if(flag == 0)
                {
                    cout<<"no"<<endl;
                }
            }
        }

    }


    return 0;
}

T2:清华售货机

清华大学的自动售货机一共有 𝑛 种饮料出售,每种饮料有自己的售价,并在售货机上各有一个出售口。购买第 𝑖 种饮料时,可以在第 𝑖 个出售口支付 𝑎𝑖 的价格,售货机便会在下方的出货处放出对应的饮料。

又到了清凉的夏日,自动售货机为每种饮料各进货了1 瓶存储在其中,供同学购买。但是,自动售货机却出现了一些故障,它有可能会出货不属于这个出售口的饮料。

对于第 𝑖 个出售口,支付 𝑎𝑖 的价格购买后,如果饮料 𝑖 与饮料 𝑏𝑖 都有存货,有 𝑝𝑖 的概率出货饮料 𝑖 ,有 1−𝑝𝑖 的概率出货饮料 𝑏𝑖 。如果其中一个有存货,另一个已经没有存货,则将出货有存货的那一种饮料。如果两种饮料都没有存货,售货机将不会出货任何饮料并发出警报。**即便最后你没有获得任何饮料,也需要支付 𝑎𝑖 的价格 ** 。

长颈鹿下楼来到这台售货机前,希望能买到最近火爆全网的饮料 𝑥 ,此时售货机中 𝑛 种饮料都存货有 1 瓶。由于他知道售货机有问题,因此决定采取这样的策略来购买:

  • 在 𝑛 个出售口中等概率选择一个出售口 𝑠 开始购买,支付这个出售口的价格 𝑎𝑠 并得到出货。
  • 当得到想要的饮料 𝑥 时,停止购买流程,满意欢喜的离去。
  • 当得到不想要的饮料 𝑦 时,继续在第 𝑦 个支付口购买,支付 𝑎𝑦 的价格并等待出货。
  • 当售货机发出警报时,停止购买流程,灰心丧气的离去。

现在他希望你告诉他,他这一次购买过程期望支付的价钱数量是多少?

解:

思路很简单,利用vec容器,然后按照题目的 思路,找到2个递归出口,写出递归函数即可!

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<string>

//售货机 -- 大概率是 模拟题
//一共n种饮料,第i个出售口售价ai
//每种饮料 只有 1 瓶
//故障!
//支付ai后,如果饮料i和饮料bi都有存货:pi概率获得饮料i,1-pi获得另一种
//一种就直接出,否则什么都没有

//策略:
//等概率的选择一个出售口s,并以as支付
//直到获取y
//或者没有出货
//根据输入数据,计算输出一个期望的 价格?

using namespace std;


int x= 0;
int n;

struct drink
{
    double a;   //价格
    int  b;     //另一个饮料的编号 - 下标从1开始用
    double p;   //抽中i的概率

    int flag = 0; //flag = 0代表 这个i饮料还在
    //默认构造:
    drink()
    {
        this->flag= 0;
        this->a = 0; this->b =0; this->p = 0;
    }
};

vector<drink> vec;  //全局

//处理输入:
void init()
{
    cin>>n>>x;
    drink tmp2;
    vec.push_back(tmp2); //index==0位置不用
    for(int i =1 ;i <=n;i++)
    {
        drink tmp;
        cin>>tmp.a>>tmp.b>>tmp.p;
        vec.push_back(tmp);
    }
}

//递归函数:func
double func(int i)
{
    double pi = vec[i].p;
    double ai = vec[i].a;
    int    bi = vec[i].b;

    double ans = ai;  //因为这一次选择了ai,一定会有一个基础的ai的钱需要花
    //选择第i个出货口后,进行递归模拟,出口是命中x或者i和bi都没了
    //case1:
    if(vec[i].flag == 0 && vec[bi].flag == 0)
    {
        //i 和 bi都还在:
        double ans1 = 0;
        double ans2 = 0;
        //出货了 饮料i:
        vec[i].flag = 1;
        if(i == x)
        {
            //ans1 = pi*ai;
            ans1 = 0;
        }
        else{
            ans1 = pi*func(i);
        }

        //出货了 饮料bi
        vec[i].flag = 0;  //补货
        vec[bi].flag = 1; //出货
        if(bi == x)
        {
            //ans2 = (1-pi)*ai;
            ans2 = 0;
        }
        else{
            ans2 = (1-pi)*func(bi);
        }

        //-返回:
        //flag 改回去:
        vec[i].flag = 0;
        vec[bi].flag = 0;
        ans = ans + ans1 + ans2;
        return ans;

    }

    //case2:
    if(vec[i].flag == 0 && vec[vec[i].b].flag != 0)
    {
        //只有 饮料i在 - 必定是出饮料i:
        //如果饮料i 不是x 就必定凉凉:
        if(x == i)
        {
            return ans;
        }
        else
        {
            ans = ans + ai;
            return ans;
        }

    }

    //case3:
    if(vec[i].flag != 0 && vec[vec[i].b].flag == 0)
    {
        //此时bi可能需要进行递归:
        if(bi == x) 
        {
            return ans;
        }
        else
        {
            vec[bi].flag = 1; //此时bi已经出货了
            ans = ans + func(bi);

            //记得返回之前完成补货:
            vec[bi].flag = 0;

            return ans;
        }
    }

    //case4:
    if(vec[i].flag != 0 && vec[vec[i].b].flag != 0)
    {
        return ans;
    }

}


int main()
{
    init();
    //开启模拟
    double p0 = (double)(1/(double(n)));
    double myans = 0;
    for(int i = 1 ; i <=n ;i++)
    {
        myans = myans + p0*func(i);
    }
    cout<<myans<<endl;
    

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值