2024.3.6补题

1.关鸡

对于这一道题,我们先按照题意进行分析:首先鸡自己的初始位置,如果着火点在鸡一开始的左右下各有一个那么就可以达到题目效果,也就是说不需要添加着火点,同时最多需要添加的着火点其实也就是它初始位置身边所有的三个位置,也就是最多需要添加三个着火点。另外考虑当着火点在更远的位置的时候,我们容易想到当有两个着火点是上下挨着的时候,这两个挨着的着火点就可以拦住鸡通往的一边了,另一边也是同理,我们可以考虑通过映射的方式,将已经有着火点的位置设置成1,同时通过位运算代替if else减少代码量,对于每组测试案例,我们可以考虑分别对鸡的左右边进行判断,不妨引入l与r,代表两边对鸡逃亡有意义的着火点个数。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int T;
int n;
map<int,int>m[2];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin>>T;
    while(T--){
    cin>>n;
    int l=0,r=0;
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x>>y;
        x--;
        if(y>=0) r=max(r,1);
        if(y<=0) l=max(l,1);
        if(m[x^1][y]){
            if(y>=0) r=max(r,2);
            if(y<=0) l=max(l,2);
        }
        if(y>=0 && m[x^1][y+1])  r=max(2,r);
        if(y<=0 && m[x^1][y-1])  l=max(2,l);
        if(y>0  && m[x^1][y-1])  r=max(2,r);
        if(y<0  && m[x^1][y+1])  l=max(2,l);
        m[x][y]=1;
    }
        int ans=4-l-r;
        if(m[0][1])  ans=min(2,ans);
        if(m[0][-1]) ans=min(2,ans);
        if(m[0][-1] && m[0][1]) ans=min(ans,1);
        ans=min(ans,3);
        cout<<ans<<endl;
        m[0].clear(),m[1].clear();
    }
    return 0;
}

 上述代码中x输入之后记得减去1,因为题目中只有两行,我们分别用0 1代表原本的第一行和第二行,ans的初始值设置成4,这样假设鸡的左右两边都没有着火点,然后再通过输入慢慢更新l与r最终与ans相减就可以了,然后对于每个输入的着火点,我们判断它的身边是否还有着火点,如果有就说明这一边鸡无论如何都跑不过去了,最后特判一下当鸡的出生点身边有着火点的情况即可。

2.按闹分配:

 分析:由于有n个人在排队,并且工作人员会根据每个人手续处理时间合理安排排队顺序,这里我们需要想到必定是按照办理手续时间从短到长的方式进行的;同时我们可以发现,每一个人的不满意度其实就是从他开始排队到事情办完一共花了时间,所以也就是他排队前面的所有人的办理时间以及他自己的手续时间,那么我们就要想到,当鸡插队了之后,他后面的所有人都会增加他手续时间的不满意度。

我们不妨考虑先对来办事的所有人按照时间短到长排序,再用前缀和来记录在鸡没插队之前,每个人的不满意度,那么答案就是鸡前面的位置所对应的前缀和数组下标答案加上他自己的手续时间,这时候我们就只需要考虑怎么写代码判断鸡最早在哪里插入队中去是合适的。

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, q, t, a[N];
long long m, s[N];
int main()
{
    ios::sync_with_stdio(0);
    cin >> n >> q >> t;
    for(int i = 1; i <= n; ++i) cin >> a[i];
    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
    while(q--){
        //这里题目中需要思考到,当鸡插入之后,他后面的所有人的不满意度都要加上一个t,从而使得Sc=Smin+t*n;
        //题目中的判断条件可以由Sc-Smin<=M 换成 t*n<=M
        cin >> m;
        m /= t;
        if(m >= n) cout << t << endl;
        else cout << s[n - m] + t << endl;
    }
    return 0;
}

3.数组成鸡:

  分析:对于此题,我们发现数据范围相对较大,所以如果要通过所有的测试案例,暴力肯定是行不通的,我们要考虑通过怎样一种巧妙的方式来完成此题的解答:

由于我们可以进行任意次操作,我们可以考虑利用最大值和最小值做基准进行两次判断,先把数组从小到大排序然后让每个数组元素都减去第一个元素,因为反正可以任意次操作,所以其实可以对数组所有元素同时加减任意整数,然后我们考虑利用一个循环表示将数组元素进行加对应值是否满足要求,边输入边进行判断是否会超过询问数字的最大值,当全部乘完并且发现不会超过1e9的时候,我们利用一个映射,将这个乘完的数字给他设置为bool中的true,这样当询问中问到某个数字的时候我们可以根据它是否被设置为true来判断是否满足题意。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[200010];
signed main()
{
	map<int,bool>mp;
	mp[0]=true;
	int n,q;
	scanf("%lld%lld",&n,&q);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+1+n);
	for(int i=n;i>=1;i--)
	{
		a[i]-=a[1];
	}
	if(n==1)
	{
		while(q--)
		{
			int t;
			cin>>t;
			puts("Yes");
		}
		return 0;
	}
	for(int add=-100000;add<=100000;add++)
	{
		int res=1;
		bool ok=true;
		for(int i=1;i<=n;i++)
		{
			res*=(a[i]+add);
			if(abs(res)>=1e9)
			{
				ok=false;
				break;
			}
		}
		if(ok)mp[res]=true;
	}
	int tem=a[n];
	for(int i=n;i>=1;i--)
	{
		a[i]-=tem;
	}
	for(int add=-100000;add<=100000;add++)
	{
		int res=1;
		bool ok=true;
		for(int i=1;i<=n;i++)
		{
			res*=(a[i]+add);
			if(abs(res)>=1e9)
			{
				ok=false;
				break;
			}
		}
		if(ok)mp[res]=true;
	}
	while(q--)
	{
		int t;
		scanf("%lld",&t);
		if(mp[t])puts("Yes");
		else puts("No");
	}
	return 0;
}

4.kkksc03考前临时抱佛脚:

 对于这个题,我们其实可以将四科进行单独的考虑,同时我们可以看到主人公的大脑可以两个脑子分别解答一道题,对于每一个科目,当题目数量为1的话那么毫无疑问这一科目的时间就是完成该课程复习的时间,而当有多道题目的时候,我们进行思考后会发现,两个大脑由于可以同时运转,同时解答两道题目,那么我们会发现如果要得到最短时间,那么我们其实也就是尽可能在多的时间内两个大脑同时运转,其中一个大脑的运算时间一定是小于等于另一个大脑的,所以这一个题我们可以考虑利用01背包的方式进行解答,接下来请看代码;

#include<bits/stdc++.h>
using namespace std;
const int N=30;
const int TIME=1300;
int a[5],homework[N],dp[N][TIME];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin>>a[1]>>a[2]>>a[3]>>a[4];
    int t=0;
	for(int i=1;i<=4;i++){	
	   	int sum=0;
		   for(int j=1;j<=a[i];j++){
	   		    cin>>homework[j];
				sum+=homework[j];
		   }
		   memset(dp,0,sizeof(dp));
		   for(int j=1;j<=a[i];j++){
		   	for(int k=1;k<=sum/2;k++){
		   		dp[j][k]=max(dp[j-1][k],k>=homework[j] ? dp[j-1][k-homework[j]]+homework[j]:0);
			   }
		   }
		 t += sum-dp[a[i]][sum/2];  
	}
	cout<<t<<endl;
	return 0;   
}

5.马走日:

 这道题目只需要分类讨论就行了,我们不妨把n,m看成一个直角坐标系,n,和m对应x和y的边界,我们由于并不确定n和m谁打谁小,不妨通过小的那个来进行研究,因为其实,x,y坐标都是选择其中一个走一步另一个走两步,当n为1,2,3分别进行考虑(其实都可以在草稿本上面斗出来),然后直接按照规律输出就行了:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
inline void solve(){
         scanf("%lld%lld",&n,&m);
         if( n > m)  swap( n , m );
         if( n == 1 ) puts("1");
    else if( n == 2 ) printf("%lld\n",( m  + 1 ) / 2);
    else if( n == 3 ) printf("%lld\n",( m == 3 ) ? 8 : m * n);
    else printf("%lld\n",m * n);
}
signed main(){
    int testcase; 
    scanf("%lld", &testcase);
    while(testcase--) solve();
    return 0;
}

今日份任务完成,感谢您的观看,希望对你有所帮助!

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

残念亦需沉淀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值