目录
C. Monsters And Spells
原题描述
题意理解
这是一个游戏。在第i秒时,可能会出现血量为hi的怪兽。所幸你会魔法,你释放法术造成的伤害和你已经连续释放次数是相同的,比如你连续释放3次法术,这三次依次能造成的伤害为1,2,3,你随时可以重置连续释放次数,如比可以造成如下伤害1,2,3,1,2。你要在每一只怪物出现那一刻用法术把他消灭掉。在没有怪物时也能释放法术。释放法术是需要魔力值的,释放一个法术所花费的魔力值与该法术可能造成的伤害相同。
输入怪物的数量,然后是出现怪物的时刻和该怪物的血量。输出最小的法力值花费。
举例
有3只怪兽出现在第5,7,9秒,血量依次为2,1,2。
我们在第4秒时开始释放法术,当前伤害为1,花费1点法力。第五秒伤害为2,花费2点法力,正好与第五秒出现怪兽的血量相同。第六秒不释放,第七秒释放一次,伤害与血量相同,花费1点法力。第8秒重置连续释放次数,造成伤害为1,花费1点法力。第9秒,连续释放,造成伤害为2,与怪物血量对应,花费2点法力。
总的法力花费为1+2+1+1+2=7。
输出7即可。
题解
我们关注怪物出现的时刻法术的伤害。
因为我们要追求最小的法术消耗,所以我们假定在第i只怪兽时,我们法术的伤害等于该怪兽的血量。
什么情况下该假设不能成立呢?
1.第i时刻与i-1时刻的间隔小于怪兽的血量时。
2.值得注意的是,必须满足所有的怪兽都能受到大于他们血量的攻击。假设我们当前的法术伤害一直叠加,但是到了某一只怪兽出现时无法大于他的血量,代表着我们当前的法术伤害低了。
以上两种情况下我们的假设都不成立。
对于第一种,我们当前释放的法术伤害等于对前一只怪兽释放的法术加上两个时刻的间隔。
对于第二种,我们直接将可以满足该条件的最小值当作假设值,再带到第一个条件里面判断,如果大于i与i-1的时间间隔,改假设值成立,否则当前释放的法术伤害等于对前一只怪兽释放的法术加上两个时刻的间隔。
AC代码
/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LM LLONG_MAX
#define IM INT_MAX
#define _for(i,a,b) for(int i=a;i<=b;i++)
#define N 101
struct monster{
ll s;
ll h;
};
ll sum1(ll x){
return (1+x)*x/2;
}
int main(){
int t;
cin>>t;
while(t--){
ll n,ans=0,temp=0;
monster a[N];
cin>>n;
_for(i,1,n) cin>>a[i].s;
_for(i,1,n) cin>>a[i].h;
a[0].s=0;
a[0].h=0;
int temp1=0;
_for(i,1,n){
ll temp=a[i].h;
_for(j,i+1,n) if(a[j].h-temp>a[j].s-a[i].s) temp=a[j].h-(a[j].s-a[i].s);
if(a[i].s-a[i-1].s>=temp){
ans+=sum1(temp);
temp1=temp;
// cout<<ans<<endl;
}
else{
ans+=sum1(temp1+a[i].s-a[i-1].s)-sum1(temp1);
// cout<<ans<<endl;
temp1=temp1+a[i].s-a[i-1].s;
}
}
cout<<ans<<endl;
}
}
B. Minor Reduction
原题描述
题解
第一次从后往前遍历字符串,如果两相邻数字相加大于10,进行操作,然后退出,输出即可。
如果没有一对数字相加大于10,直接对第一个数和第二个数操作放到字符串里面输出即可。
AC代码
/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LM LLONG_MAX
#define IM INT_MAX
#define _for(i,a,b) for(int i=a;i<=b;i++)
#define N 200002
int main(){
int t;
cin>>t;
while(t--){
char s[N];
bool flag=true;
cin>>s;
int len=strlen(s);
for(int i=len-1;i>=1;i--){
int temp=s[i]+s[i-1]-'0'-'0';
if(temp>=10){
s[i]=temp%10+'0';
s[i-1]=temp/10+'0';
flag=false;
break;
}
}
if(flag){
s[1]=s[0]+s[1]-'0';
_for(i,1,len-1){
cout<<s[i];
}
}
else _for(i,0,len-1)
cout<<s[i];
cout<<endl;
}
}
A. Equidistant Letters
题解
拿一个数组当桶,记录字母出现个数,然后输出即可。
AC代码
/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LM LLONG_MAX
#define IM INT_MAX
#define _for(i,a,b) for(int i=a;i<=b;i++)
int main(){
int t;
cin>>t;
while(t--){
string s;
int a[30]={0};
cin>>s;
int len=s.length();
_for(i,0,len-1){
a[s[i]-'a']++;
}
_for(i,0,25){
if(a[i]==0) continue;
if(a[i]==1){
char temp=i+'a';
cout<<temp;
}
if(a[i]==2){
char temp=i+'a';
cout<<temp<<temp;
}
}
cout<<endl;
}
}
D. Martial Arts Tournament
题解
暴力求解,直接模拟出所有x,y可能的取值即可。
AC代码
/*@_krito*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LM LLONG_MAX
#define IM INT_MAX
#define _for(i,a,b) for(int i=a;i<=b;i++)
#define N 200010
int n;
int s[N];
int cmp(int x,int y){
// cout<<x<<y<<endl;
int temp1=1,temp2=1,temp3=1;
while(temp1<x) temp1*=2;
while(temp2<y-x) temp2*=2;
while(temp3<n-y) temp3*=2;
return temp1-x+temp2-y+x+temp3-n+y;
}
int main(){
int t;
cin>>t;
while(t--){
int a[N]={0},ans=IM;
scanf("%d",&n);
_for(i,1,n){
int x;
scanf("%d",&x);
a[x]++;
}
_for(i,1,n){
s[i]=s[i-1]+a[i];
}
_for(i,1,n+1){
int tempx=s[i-1];
for(int j=0;(1<<j)<=n-tempx;j++){
if(j==1){
int tempy= upper_bound(s+1,s+1+n,tempx+j)-s;
tempy=s[tempy-1];
ans=min(ans,cmp(tempx,tempy));
tempy=lower_bound(s+1,s+1+n,n-j)-s+1;
tempy=s[tempy-1];
ans=min(ans,cmp(tempx,tempy));
}
int tempy= upper_bound(s+1,s+1+n,tempx+(1<<j))-s;
tempy=s[tempy-1];
ans=min(ans,cmp(tempx,tempy));
tempy=lower_bound(s+1,s+1+n,n-(1<<j))-s+1;
tempy=s[tempy-1];
ans=min(ans,cmp(tempx,tempy));
}
}
printf("%d\n",ans);
}
}