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转移式为:
            
其中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天后最大的产值

本题为数据结构+反悔贪心(具体可以是线段树,对顶堆,树状数组)

#include<bits/stdc++.h>
using namespace std;
#define int long long
struct heap{
    priority_queue<int> big;
    priority_queue<int,vector<int>,greater<int>> small;
    int sumi=0;
    void insert(int x){
        if(!small.empty() && x>small.top()){
            int mi=small.top();small.pop();
            sumi-=mi;
            big.push(mi);
            small.push(x);
            sumi+=x;
        }else{
            big.push(x);
        }
    }
    void resize(int k){
        while (small.size() > k) {
            int y = small.top(); small.pop();
            sumi -= y;
            big.push(y);
        }
        while (small.size() < k && !big.empty()) {
            int y = big.top(); big.pop();
            sumi += y;
            small.push(y);
        }
    }
    int getsum()const{return sumi;}
    int total()const{return small.size()+big.size();}
};
void solve(){
    int n ;cin>>n;
    vector<pair<int, int>> a(n+1);
    vector<int> wpos;
    for (int i = 0; i < n; ++i) {
        char op;cin>>op;
        if (op == 'W') {
            a[i] = {0, 0};
            wpos.push_back(i);
        } else {
            int x;cin>>x;
            a[i] = {1, x};
        }
    }
    if (wpos.empty()) { cout<<0<<'\n'; return; }
    heap hp;
    int ans = 0;
    for (int i = 0; i < wpos[0]; i++) if (a[i].first == 1) hp.insert(a[i].second);
    for (int idx = 0; idx < wpos.size(); idx++) {
        int L = wpos[idx];
        int R = (idx + 1 <wpos.size()) ? wpos[idx + 1] - 1 : n - 1;
        int D = R - L + 1;
        vector<pair<int, int>> fv;
        for (int j = L + 1; j <= R;j++) {
            if (a[j].first == 1) {
                int x = a[j].second;
                fv.push_back({x * (R - j + 1), x});
            }
        }
        sort(fv.begin(), fv.end(), greater<pair<int,int>>());
        vector<int> pref(fv.size() + 1, 0);
        for (int j = 0; j < fv.size(); j++) pref[j+1] = pref[j] + fv[j].first;
        int sumw = idx + 1;
        int past = hp.total();
        int mik = max(0LL, sumw - (signed)fv.size());
        int mxk = min(sumw, past);
        int best = 0;
        if (mik > mxk) {
            hp.resize(past);
            best = D * hp.getsum() + pref[fv.size()];
        } else {
            hp.resize(mik);
            int sumcur = hp.getsum();
            for (int k = mik; k <= mxk; ++k) {
                int v = D * sumcur + pref[sumw - k];
                if (v > best) best = v;
                if (k < mxk) {
                    int y = hp.big.top(); hp.big.pop();
                    hp.small.push(y);
                    hp.sumi += y;
                    sumcur = hp.sumi;
                }
            }
        }
        ans += best;
        for (auto &p : fv) hp.insert(p.second);
    }
    cout << ans << '\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    cin>>_;
    while(_--){
        solve();
    }
}

作者有点忙就先直接放AC代码了(其实是懒得打字())

E斗地主

题意:给出n表示牌的最大数字,之后给出A和B拥有的牌的情况(字符串,0表示没有这张牌,1表示有一张单牌,2表示有一对牌),A和B为农民,C为地主且只有一张单牌,题目让你判断农民能否胜利(题目要求对子不能拆成俩张单牌),A先手且必须出牌。
    首先我们可以先记录下A的单牌和双牌,B的单牌和双牌。由于地主只有一张单牌,所以所有的对子都是安全牌,而大于等于地主的牌(以下简称pc)的单牌(以下简称大牌,小于的称为小牌)也是安全牌。
    显而易见得,如果A的单牌都比pc大或者没有单牌(或者剩下一张比pc小的单牌放最后出),那么B只需要一直pass就可赢,但是如果A的单牌有比pc小的,就需要B去拿大的牌压小牌,让C出不了牌。这是A让农民赢的情况(具体后面会讨论)
    我们思考是否能有B让农民赢的情况?实际上,如果B有牌权,且B的单牌都比pc大或者没有单牌(或者剩下一张比pc小的单牌放最后出),那么B也能让农民赢,但是B如果有小牌,且个数≥2,那么B就不可能让农民赢,因为如果B出掉其中一张小牌,C立马可以打出进而赢得比赛。
    那么考虑农民是否能胜利​​​的关键就转移到了牌权上:
    1.我们考虑B能让农民赢的前提条件就是B能够拿到牌权
    2.我们考虑B帮A让农民赢的前提条件是B用大牌压A的小牌之后A仍然能重B那里拿回牌权
    而让B拿到牌权的条件是:A有比B小的单牌或双牌
    而让A拿回牌权的条件是:B有比A大的单牌(且这张单牌大于pc)或B有比A大的双牌
作者自我感觉这题是思维题,但是非常绕且很有可能有情况没考虑到(因为这个WA了好几发,也可能是作者水平有限)
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){
    int n;cin>>n;
    vector<int> Aji,Aou,Bji,Bou;
    for(int i=1;i<=n;i++){
        char x;cin>>x;
        if(x=='0')continue;
        else if(x=='1')Aji.push_back(i);
        else Aou.push_back(i);
    }
    for(int i=1;i<=n;i++){
        char x;cin>>x;
        if(x=='0')continue;
        else if(x=='1')Bji.push_back(i);
        else Bou.push_back(i);
    }
    int lmt;cin>>lmt;

    int need=0;
    for(int i=0;i<Aji.size();i++){
        if(Aji[i]<lmt)need++;
        else break;
    }
    need--;
    if(need<=0){
        cout<<"Yes\n";
        return;
    }

    bool ok=false;
    int cntB=0;
    for(int i=0;i<Bji.size();i++){
        if(Bji[i]<lmt)cntB++;
        else break;
    }
    if(Aji.size() && Bji.size() && Bji[Bji.size()-1]>Aji[0] && Bji[Bji.size()-1]>=lmt)ok=true;
    if(Aou.size() && Bou.size() && Bou[Bou.size()-1]>Aou[0])ok=true;
    if(ok){
        if(cntB<=1){
            cout<<"Yes\n";
            return;
        }
    }
    if(Bji.size()==1 && Bou.size()==0 && Aji.size() && Bji[0]>Aji[0]){
        cout<<"Yes\n";
        return;
    }

    if(need>Bji.size()-cntB){
        cout<<"No\n";
        return;
    }
    int chg1=0;
    for(int i=need,j=cntB;i<Aji.size() && j<Bji.size();i++){
        if(Aji[i]>Bji[j]){
            chg1++;
            j++;
        }
    }
    int chg2=0;
    for(int i=0,j=0;i<Aou.size() && j<Bou.size();i++){
        if(Aou[i]>Bou[j]){
            chg2++;
            j++;
        }
    }
    if(chg1+chg2>=need)cout<<"Yes\n";
    else cout<<"No\n";
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    cin>>_;
    for(int i=1;i<=_;i++){
        solve();
    }
}
/*
1
9
110200000
222000000
7

*/

 

posted on 2026-04-30 15:53  LeoCodex  阅读(6)  评论(0)    收藏  举报