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);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84370971
RPG