2018-2019 ACM-ICPC, Asia Jiaozuo Regional Contest B - Ultraman vs. Aodzilla and Bodzilla 貪心

題目鏈接:https://codeforces.com/gym/102028/problem/B

題目描述:

奧特曼打怪獸,有怪獸aabb 分別對應的生命值爲HPaHPbHP_a,HP_b和攻擊力ATKa,ATKbATK_a,ATK_b,按回合制進行攻擊,如果怪物活着,將對奧特曼先造成對應的傷害,在第ii回合奧特曼打怪的傷害爲ii,問奧特曼殺死這兩隻怪獸後受到的最小傷害,並對應輸出字典序最小的方案

題解思路:

在貪心上的最優方案一定是優先殺一個人,再殺另一個。
f(x)f(x)表示對一個怪獸造成xx點傷害的最小步數,就是等差數列求個和。
那麼我們一定可以在f(HPa+HPb)f(HP_a+HP_b)的時間將兩者全部殺掉。
假設先殺aa我們總可以保證在f(HPa)f(HP_a)的時間殺死aa並且不浪費一點攻擊力,即在[1,f(HPa)][1,f(HP_a)]的時間穿插着打bb,並且殺死aa

接下來分兩種策略,分別是先殺a和先殺b。
先用三次二分搜索找出len,len1,len2len,len1,len2分別對應殺光,殺aa,殺bb對應的最小步數。

如果先殺aa的話,就是在[1,len1][1,len1]穿插打bb,並打死aa(len1,len](len1,len]全部打bb
現在的問題就是如何分配打bb,保證這個字符串字典序最小。
現在有一個nednedleflef表示還需要多少打bb(可能不需要),和打aa的部分可以給多少出去。
我們就倒序在[1,len1][1,len1]找,如果需要,並且有剩餘,就替換爲BB

第二種情況是先殺bb的策略,這種策略在[1,len2][1,len2]分配打法的時候思維上比較複雜= =
在貪心策略上,依舊考慮nednedleflef
順序循環填AA的情況會出現當前如果填了AA之後後面無法再填A(leflef不夠了),這個時候就需要移動一下填AA的位置到需要的地方。這種情況在第一個策略裏面就不需要考慮,因爲倒序循環不會出現這種情況。

#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
#define int ll
#define debug cout<<"fuck"<<endl;
const int mod=(int)1e9+7;
const int maxn=(int)3e5+5;
int a[maxn];
int len,len1,len2;
int n,t;
int h1,h2,a1,a2,hur1,hur2;

bool check(int x,int ned)
{
    ll sum=(x+1)*x/2;
    if(sum<ned)return 0;
    else return 1;
}
int sum(int l,int r)
{
    return (r-l+1)*(l+r)/2;
}

int cmp(string a,string b)
{
    for(int i=1;i<min(a.size(),b.size());i++)
    {
        if(a[i]==b[i])continue;
        else return a[i]>b[i]?1:2;
    }
    return a.size()>=b.size()?1:2;
}

int binary_search(int x)
{
    int l=1,r=(int)1e9,mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(check(mid,x))r=mid;
        else
        {
            l=mid+1;
        }
    }
    return l;
}

string kill_a()
{
    string s="";
    s+='0';
    int ned=h2;
    int lef=sum(1,len1)-h1;
    for(int i=1;i<=len;i++)
    {
        if(i<=len1)s+='A';
        else
        {
            s+='B';
            ned-=i;
        }
    }
    for(int i=len1;i>=1&&ned>0;i--)
    {
        if(lef>=i)//如果需要,並且有剩餘
        {
            lef-=i;
            ned-=i;
            s[i]='B';
        }
    }
    return s;
}

string kill_b()
{
    string s="";
    s+='0';
    int lef=0;
    int ned=h1-sum(len2+1,len);
    for(int i=1;i<=len;i++)
    {
        if(i<=len2)
        {
            s+='B';
            lef+=i;
        }
        else s+='A';
    }
    lef-=h2;
    for(int i=1;i<=len2&&lef>0;i++)
    {
        if(lef>=i)
        {
            if(lef-i<i+1&&ned-i>0)//如果這個位置修改爲A之後,之後不能再修改了,但是還有需要
            {
                s[ned]='A';
                //cout<<"i:"<<i<<' '<<"ned:"<<ned<<endl;
                break;
            }
            lef-=i;
            ned-=i;
            s[i]='A';
        }
    }


    return s;
}

void sout(string s)
{
    for(int i=1;i<s.size();i++)
    {
        cout<<s[i];
    }
    cout<<endl;
}

signed main()
{
    IOS
    cin>>t;

    while(t--)
    {
        cin>>h1>>h2>>a1>>a2;
        len=binary_search(h1+h2);
        len1=binary_search(h1);
        len2=binary_search(h2);
        hur1=len1*(a1+a2)+(len-len1)*a2;
        hur2=len2*(a1+a2)+(len-len2)*a1;

        string fir_kil_a=kill_a();
        string fir_kil_b=kill_b();

        //cout<<hur1<<' '<<fir_kil_a<<endl;
        //cout<<hur2<<' '<<fir_kil_b<<endl;

        if(hur1<hur2)
        {
            cout<<hur1<<' ';
            sout(fir_kil_a);
        }
        else if(hur1>hur2)
        {
            cout<<hur2<<' ';
            sout(fir_kil_b);
        }
        else
        {
            if(cmp(fir_kil_a,fir_kil_b)==1)//a大
            {
                cout<<hur2<<' ';
                sout(fir_kil_b);
            }
            else
            {
                cout<<hur1<<' ';
                sout(fir_kil_a);
            }
        }
    }


    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章