L暴击率
题意:给出n个物品和m个硬币,每个物品有概率p,暴击率v,花费w。你可以用m个硬币买物品(每个不超过一个),在在所有可能情况中,当多个装备同时触发暴击时,只有最高的暴击倍率生效。求可能得到的最大期望。
本题为概率DP(01背包变式)
考虑01背包可以求取当花费j个硬币时期望的最优解(1 <= j <= m)本题要求最大期望,可以遍历所有j个硬币的期望取最大值来求解
(这题和01背包不同的地方就是01背包当花费越大时,能够获得的价值是递增的,但是这道题中当花费越大时,期望不一定是全局最大的,只能说是该花费时的最优解,因此要遍历求最大值)
为什么说这题是概率dp呢?其实就是在求解最优解时我们需要对暴击率从小到大排序,这样去枚举每个物品时,只会出现俩种情况:假设该物品为i,且暴击率为pr,一种是该物品暴击了,那么它对总期望的贡献就是pr*v;另外一种情况是该物品没暴击,那么它对期望的贡献是前一个期望最优解 dp[i-1]*(1-pr),因此,dp转移式为:
%2Bpr*v))
其中j为硬币数,完整代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct pi{
double p,v,cst;
};
bool cmp(pi a,pi b){
return a.v<b.v;
}
void solve(){
int n,w;
cin>>n>>w;
vector<pi> a;
for(int i=1;i<=n;i++){
double p,v,cst;
cin>>p>>v>>cst;
a.push_back({p,v,cst});
}
sort(a.begin(),a.end(),cmp);
vector<double> dp(w+10,0.0);
for(int i=0;i<n;i++){
double pr=1.0*a[i].p/100.0;
for(int j=w;j>=a[i].cst;j--){
dp[j]=max(dp[j],dp[j-a[i].cst]*(1.0-pr)+a[i].v*pr);
}
}
double ans=-1e18;
for(int i=0;i<=w;i++)ans=max(ans,dp[i]);
cout<<fixed<<setprecision(12)<<ans<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
}
G贪吃蛇吃苹果
题意:(本题为交互题)给出n*m的网格,贪吃蛇初始长度为1,可以用UDLR来表示头向上下左右4个方向移动,给出起点坐标,之后每次给出一个苹果坐标,一个给出n*m-1次,要求蛇不能越界并且不能碰到自己的身体,每给出一个苹果打出一个字符串表示蛇的移动过程,要求吃掉所有苹果。
本题为构造
相信大家很容易想到,在存在一边长度大小为偶数的情况下,可以构造出哈密顿回路:
只要蛇一直沿着该哈密顿回路走总是能吃掉苹果,之后就是本题最难的点:如何处理奇数*奇数的情况:
首先,交互题有一个特点,你可以自适应它给出的数据,那就意味着你可以根据它给出的坐标修改你的实现方式。然后我们就开始思考能否在奇数*奇数网格中构造出类似的哈密顿回路并能够根据坐标位置进行调整。相信聪明的你这时候会想到这种情况:(构造题的特性:灵光一闪!!)
我们可以在一个拐角预留出一个格子,其余格子构成一个哈密顿回路,此时就可以充分利用交互题的特性:交互!!
具体代码就是先打表,然后奇数*奇数的时候根据苹果坐标特判即可。完整代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,m,stx,sty;
vector<vector<char>> e(105,vector<char>(105));
struct pi{
int x,y;
};
pi query(int sx,int sy,bool isji){
int curx=sx,cury=sy;
int x,y;
cin>>x>>y;
if(isji){
if(e[1][2]=='D'){
if(x==1 && y==1)e[1][2]='L';
}else{
if(x==2 && y==2)e[1][2]='D';
}
}
while(!(curx==x && cury==y)){
cout<<e[curx][cury];
if(e[curx][cury]=='L'){
cury--;
}else if(e[curx][cury]=='R'){
cury++;
}else if(e[curx][cury]=='U'){
curx--;
}else{
curx++;
}
}
cout<<endl;
return {x,y};
}
void solve(){
cin>>n>>m>>stx>>sty;
pi point={stx,sty};
if(n%2==0 || m%2==0){
if(n%2==0){
for(int i=1;i<=n;i++)e[i][1]='D';
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
if(i==1)e[i][j]='L';
else if(i%2==0){
if(j!=m)e[i][j]='R';
else e[i][j]='U';
}else{
if(j!=2)e[i][j]='L';
else e[i][j]='U';
}
}
}
e[n][1]='R';
}else{
for(int j=1;j<=m;j++)e[n][j]='R';
for(int j=1;j<=m;j++){
for(int i=1;i<=n-1;i++){
if(j==1)e[i][j]='D';
else if(j%2==0){
if(i!=1)e[i][j]='U';
else e[i][j]='L';
}else{
if(i!=n-1)e[i][j]='D';
else e[i][j]='L';
}
}
}
e[n][m]='U';
}
for(int i=1;i<=n*m-1;i++){
int curx=point.x,cury=point.y;
point=query(curx,cury,false);
}
}else{
for(int j=1;j<m;j++)e[n][j]='R';
e[n][m]='U';
for(int j=3;j<=m;j++){
for(int i=1;i<=n-1;i++){
if(j%2==1){
if(i!=1)e[i][j]='U';
else e[i][j]='L';
}else{
if(i!=n-1)e[i][j]='D';
else e[i][j]='L';
}
}
}
e[1][1]='D';e[1][2]='D';
for(int i=2;i<=n-1;i++){
if(i%2==0){
e[i][1]='D';e[i][2]='L';
}else{
e[i][1]='R';e[i][2]='D';
}
}
for(int i=1;i<=n*m-1;i++){
int curx=point.x,cury=point.y;
point=query(curx,cury,true);
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=m;j++)cout<<e[i][j]<<' ';
// cout<<'\n';
// }
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--){
solve();
}
}
D工厂管理
题意:给出n天,每天可以开一家工场,且告诉你工场一天可以生产的价值v或者招进一名工人。对于建工程的那一天你可以把闲置工人放到该工场(一个工场只能有一名工人),不可改变原先已经有工作的工人。对于一名新进的工人,你可以在这一天调配所有的工人,来使最终的产值最大化(可以预留工人),输出n天后最大的产值本题为数据结构+反悔贪心(具体可以是线段树,对顶堆,树状数组)

京公网安备 11010502036488号