Rpg - dp - 結論 - 數論分塊
阿新 • • 發佈:2018-11-26
題目大意:
這個RPG採用回合戰鬥,怪物只有一種,但是個數無限多,小X初始攻擊力為1,防禦力為0。小X的生命也是足夠多。每消滅一次怪物,小X可以得到一個金幣,這個金幣可以增加1攻擊或1防禦。回合規則如下:小X攻擊一次怪物,然後怪物攻擊小X,傷害為對方的攻擊減去己方的防禦,如果這個值小於零,則不造成傷害。當怪物生命為0時,戰鬥結束。你很容易理解,小X總有一個時候會變得無敵,但是小X想知道在變無敵之前至少承受多少傷害。
題解:
先跑一個暴力dp,然後觀察一下,發現性質是一定先加攻擊,再加防禦。
代價轉為下取整後可以數論分塊,顯然同一塊取塊的左端點最優。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int t[100];
inline int pr(unsigned __int128 x)
{
int c=0;if(!x) return !printf("0\n");
while(x) t[++c]=int(x%10),x/=10;
for(int i=c;i;i--) printf("%d",t[i]);
return 0;
}
int main()
{
lint att,hp;cin>>att>>hp,hp--;
unsigned __int128 m=(unsigned __int128)att*(att+1)/2;
unsigned __int128 ans=0,v=0,w;ans--;
for(lint s=1,t;s<=hp;s=t+1)
w=hp/s,t=hp/w,
ans=min(ans,w*m+att*v),
v+=(unsigned __int128)w*(t-s+1);
return ans=min(ans,att*v),pr(ans);
}