第四次积分赛题解

7-1.由于操作三四是可以将手中任意食物放回,所以可以先拿好,最后再考虑要放回那些食物,

单独考虑操作一二,因为只能从两边拿,我们考虑用前缀和维护(好像也没用上。。。)。详见代码注释

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
int n,k,p[N],tt,sun=0;
void solve(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>p[i];
		if(p[i]<0){
			tt++;
		}else sun+=p[i];
		p[i]+=p[i-1];//前缀和
	}
	int ans=0;//记录答案
	for(int i=1;i<=k;i++){//这一维遍历的是操作一二共用了多少次,因为可能拿到负的,所以要留一些操作次数来放回
		for(int l=0;l<=min(i,n);l++){//对于每一个操作一二次数和,其剩下的食物区间一定是连续的,枚举其左边界
			int r=n-(i-l)+1;//对于每一个左边界,其右边界是固定的
			r=max(l+1,r);//不能超过左边界
			priority_queue<int,vector<int>,greater<>>b;//将拿取的所有食物放入优先队列中
			for(int ii=1;ii<=l;ii++){//这是操作一拿取的那一段食物
				b.push(p[ii]-p[ii-1]);
			}
			for(int ii=r;ii<=n;ii++){//这是操作二拿取的那一段食物
				b.push(p[ii]-p[ii-1]);
			}
			int kk=k-i,sum=p[l]-p[0]+p[n]-p[r-1];
			while(kk&&!b.empty()){//对于当前i,我们最多能放回(k-i)个食物,并且只放回值为负的
				if(b.top()>=0)break;
				sum-=b.top();
				b.pop();
				kk--;
			}
			ans=max(ans,sum);//更新最大值
		}
	}
	cout<<ans;
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	while(t--){
		solve();
	}
	return 0;
}

7-2.题目名字是用来诈骗的,思考过后,我们能发现数组中位数的悲伤值一定是最小的,偶数时比较一下就好了

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[1000010];
int cheak(int x){
	int sum=0;
	for(int i=1;i<=n;i++){
		sum+=abs(a[i]-x);
	}
	return sum;
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		a[i]-=i;
	}
	sort(a+1,a+1+n);
	int k=n/2;
	cout<<min(cheak(a[k]),cheak(a[k+1]));
	return 0;
}

7-3.注意,这题只能将AB换成BA,且只能对X数组进行操作。详见注释

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;
string x,y;
int n,a,c;
void solve(){
	a=0,c=0;//a记录到当前位置时X中'A'的数量,c记录到当前位置时X中'C'的数量
	cin>>n;
	cin>>x>>y;
	for(int i=0;i<n;i++){
		if(y[i]=='C'&&x[i]!='C'){//如果当前位置的Y是C,但X不是,那无论怎样操作都不能变相等
			cout<<"No\n";
			return ;
		}
		if(x[i]=='C'&&y[i]=='C'){//遇到XY都是C的情况时,要将a,c清零,因为操作三无法隔着一个C将A换到后面
			if(a>0){//如果a没用完,此后也不能换到后面,那一定不能变相等
				cout<<"No\n";
				return ;
			}
			a=0;
			c=0;//c的清零就是将所有C变成B就好了
			continue;
		}
		if(x[i]=='A'){
			a++;
		}
		if(x[i]=='C'){
			c++;
		}
		if(y[i]=='A'){//如果当前位置Y是'A'
			if(a<=0){//如果当前A的数量已经用完
				c--;//就将一个C变成A,再通过操作三换到当前位置
				if(a<=0&&c<0){//如果A和C都用完了直接返回
					cout<<"No\n";
					return ;
				}
			}else {//如果没用完可以利用操作三将当前位置之前的A换到该位置
				a--;
			}
		}
	}
	if(a>0){//如果还有A没用,说明无法变相等了
		cout<<"No\n";
	}else cout<<"Yes\n";
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

7-4.首先当n等于1时肯定是kk输,除此之外如果kk能通过一次操作就将十一月的生命值扣完,那么kk赢,否则十一月赢。因为如果kk第一次操作没能将十一月击杀的话,如果一次攻击伤害加回合开始时的伤害能杀死kk,十一月就攻击kk,否则就给自己加血,加血后,因为上回合一次攻击加回合开始伤害无法杀死kk,因此这回合一次攻击伤害加回合开始伤害也无法杀死十一月,由于kk先受到回合伤害,且回合伤害每回合增加,所以一定是kk先死。

#include<bits/stdc++.h>
using namespace std;
int t, n, k;
int main()
{
  cin >> t;
  while(t--) {
    cin >> n >> k;
    if(n == 1) cout << "November\n";
    else {
      if(1 + k >= n) cout << "KK\n";
      else cout << "November\n";
    }
  }
}

以下奉上dfs代码可以跑过部分点,证明了正确性

#include<bits/stdc++.h>
using namespace std;
#define int long long
int dfs(int i,int a,int b,int k);
int dfs1(int i,int a,int b,int k);
void solve(){
	int n,k;
	cin>>n>>k;
	if(dfs(1,n,n,k))cout<<"KK\n";
	else cout<<"November\n";
}
signed main(){
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
}
int dfs(int i,int a,int b,int k){
	if(a<=i)return 0;
	else {
		if(b-k-i<=0)return 1;
		if(dfs1(i,a-i+k,b,k)&&dfs1(i,a-i,b-k,k))return 0;
		else return 1;
	}
}
int dfs1(int i,int a,int b,int k){
	if(b<=i)return 0;
	else {
		if(a-k-i-1<=0)return 1;
		if(dfs(i+1,a-k,b-i,k)&&dfs(i+1,a,b+k-i,k))return 0;
		else return 1;
	}
}

7-5.小模拟,只要会距离差公式应该就能写出来,注意是跟怪物的实际坐标比较,如果一直拿上一帧的来比较误差的话,误差会叠加,其中可能的坑点有:x坐标相同的情况(样例已给出),不在索敌范围的情况(样例已给出),距离小于速度的情况,判断误差的时候也是要用距离差公式求出距离来判断。

kk版ac代码

#include<bits/stdc++.h>
using namespace std;
double dis (double x, double y, double xx, double yy) {
    return 1.0 * sqrt((x - xx) * (x - xx) + (y - yy) * (y - yy));
}
int main() {
    int n;
    cin >> n;
    double s, d;
    cin >> s >> d;
    int flag = 0;
    double lastx, lasty;
    for (int i = 1; i <= n; i++) {
        double x, y, xx, yy;
        cin >> x >> y >> xx >> yy;
        if (i != 1 && dis(xx, yy, lastx, lasty) > 0.01) flag = 1;
        double nowdis = dis(x, y, xx, yy);
        //cout << flag << " " << nowdis << " ";
        if (nowdis > d) lastx = xx, lasty = yy;
        else if (s >= nowdis) lastx = x, lasty = y;
        else {
            if (x >= xx) lastx = xx + fabs(x - xx) * s / nowdis;
            else lastx = xx - fabs(x - xx) * s / nowdis;
            if (y >= yy) lasty = yy + fabs(y - yy) * s / nowdis;
            else lasty = yy - fabs(y - yy) * s / nowdis;
        }
        //cout << lastx << " " << lasty << endl;
    }
    if (flag) cout << "No";
    else cout << "Yes";
    return 0;
}

ws版ac代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
double c,d;
double dis(double a,double b,double c,double d){
	return (a-c)*(a-c)+(b-d)*(b-d);
}
signed main(){
	int n;
	double s,ded;
	cin>>n>>s>>ded;
	double k,dx,dy;
	int cc=0;
	for(int i=0;i<n;i++){
		double x,y,xx,yy;
		cin>>x>>y>>xx>>yy;
		if(i){
			double dd=dis(c,d,xx,yy);
//			cout<<dis(c,d,xx,yy)
//			cout<<dd<<c<<' '<<d<<' '<<xx<<' '<<yy<<'\n';
			if(dd>0.0001){
				cc=1;
			}
		}
		double pt=dis(x,y,xx,yy);
		if(pt>ded*ded){
			c=xx;
			d=yy;
		}else {
			if(x!=xx){
				k=(y-yy)/(x-xx);
				dx=sqrt(min(s*s,pt)/(k*k+1));
				if(x<xx)dx=-dx;
				dy=dx*k;
				c=xx+dx;
				d=yy+dy;
			}else {
				c=xx;
				if(y<yy){
					d=yy-min(s,yy-y);
				}else {
					d=yy+min(s,y-yy);
				}
			}
		}
	}
	if(cc==1){
		cout<<"No";
	}else cout<<"Yes";
	return 0;
}

7-6.模拟一下就好了,注意正负的情况

#include<bits/stdc++.h>
using namespace std;
#define int long long

signed main(){
	int x,a,d,ans=0,n;
	cin>>x>>a>>d>>n;
	if(d==0){
		cout<<abs(x-a);
		return 0;
	}
	if(x<=a){
		if(d<0){
			if(a+(n-1)*d>=x){
				ans=abs(a+(n-1)*d-x);
			}else {
				int xx=(a-x)%(-d);
				ans=min(xx,0-d-xx);
			}
			
		}else {
			ans=a-x;
		}
	}else {
		if(d>0){
			if(a+(n-1)*d<=x){
				ans=abs(a+(n-1)*d-x);
			}else {
				int xx=(x-a)%d;
				ans=min(xx,d-xx);
			}
		}else {
			ans=x-a;
		}
	}
	cout<<ans;
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值