I题: Board Game
原题链接:https://ac.nowcoder.com/acm/contest/33190/I
题目大意
有 n(1≤n≤109)n(1\le n\le 10^9)n(1≤n≤109) 个士兵攻击魔法师,这些士兵初始自由分为 m(1≤m≤107)m(1\le m\le 10^7)m(1≤m≤107) 组。
每一回合,每个存活的士兵会对魔法师造成 111 点伤害。之后魔法师选择一组士兵,击杀其中最多 k(1≤k≤107)k(1\le k\le 10^7)k(1≤k≤107) 人。
魔法师很聪明,总会采用最优策略。
如果士兵最终造成的最大总伤害不小于 x(1≤x≤1013)x(1\le x\le 10^{13})x(1≤x≤1013) ,则输出"YES"和可能造成的最大伤害,否则输出"NO"。
题解
当人数较小时,多次尝试可以发现均分是最好的策略。
对于魔法师而言,一个 x+kx+kx+k 的组等价于两个分别为 x,kx,kx,k 的组,因此我们的策略是将人划分为若干个 kkk 组,剩下的均分为 mmm 组(每组中不超过 kkk 人,否则可以继续分出)。
枚举均分组中的总人数即可。
最终的人数应该有三种, kkk 人,均分上取整人数,均分下取整人数,魔法师肯定从人数多的开始杀,分为三段等差数列求和计算伤害即可。
参考代码
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void read(T&x){
char c,last=' ';
while(!isdigit(c=getchar()))last=c;
x=c^48;
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+(c^48);
if(last=='-')x=-x;
}
#define ll long long
ll n,m,k,x;
ll ans;
void cal(ll x){//x表示k人的组数
ll rest=n-x*k;//剩下的均分人数
ll y=rest%m,z=m-y,d=rest/m,sum=0;//y为上取整人数,z为下取整人数
sum+=(n+(n-x*k+k))*x/2;//最多人组的为k人
sum+=((n-x*k)+(n-x*k-y*(d+1)+d+1))*y/2;//最多人的组为均分上取整
sum+=((z*d)+(d))*z/2;//最多人的组为均分下取整
ans=max(ans,sum);
}
int main()
{
read(n),read(m),read(k),read(x);
for(ll r=n%k,p=n%k;p<=n&&p<=r+m*k;p+=k){//r表示余数,均分部分的人数一定是r+ak的形式,枚举至r+mk即可(这时均分中上取整人数其实已经超过了m)
cal((n-p)/k);
}
if(ans>=x)cout<<"YES "<<ans<<'\n';
else puts("NO");
return 0;
}