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;
}