1. 程式人生 > >Rpg - dp - 結論 - 數論分塊

Rpg - dp - 結論 - 數論分塊

題目大意:
這個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); }