第九届“图灵杯”NEUQ-ACM部分汇总

题目

  1. NUM原题
    题意:判断一个正整数N是否可以写成a+b+a * b的形式;
    数据范围:0<N<2 * 109; a>0; b>0
    题解:考察算式变换,假设N=a*b+a+b,两边同时加1,N+1=(a+1)(b+1)。那么N+1一定是由两个大于等于2的数相乘得到的,直接检验N+1是否大于等于4和N+1是否是质数即可。
    这道题我的做法是错的,死磕于找规律,没有考虑到这样的算式变换,虽然最后过了(测试数据可能卡的不严格?),但是这里还是放一下正确题解。
#include<bits/stdc++.h>
using namespace std;
int main()
{
	/*
	考察算式变换,假设N=a*b+a+b,两边同时加1,N+1=(a+1)(b+1)。
	那么N+1一定是由两个大于等于2的数相乘得到的,
	直接检验N+1是否大于等于4和N+1是否是质数即可
	*/
	int n;
	cin>>n;
	int f=0;
	n++;
	if(n<4)
	{
		f=0;
	}
	else
	{
		for(int i=2;i<=sqrt(n);i++)
		{
			if(n%i==0)
			{
				f=1;
				break;
			}
		}
	}
	if(f==0) cout<<"No"<<endl;
	else cout<<"Yes"<<endl;
	return 0;
}
  1. 题目“特征值”
    题意:快速计算一个数字x的特征值,基于向下取整的性质,本质就是对于任意的数 ,求它本身,它去掉个位数字后剩下的数位组成的数,它去掉个位数字和十位数字后剩下的数位组成的数…直到所有数字被去掉,这些所有数的和就是它的特征值。
    数据量:1<=X<=10500000
    题解:由于数据量过大,考虑通过string或者或者字符数组完成读入,对于特征值的求取,使用竖式计算的方法,按照十进制数位来考虑,那么最终的特征值,个位上的数字就等于原数字所有数位上的数的和对10取模,十位上的数字等于去掉个位后的新数所有数位上的数的和对10取模,加上个位产生的进位(当前位上所对应的所有数的和除以10会进位到高一位),以此类推,对于从低到高 第i位上的数字就等于 原数 去掉 从1到i-1位后的新数所有数位上的数的和 对10取模,加上i-1位产生的进位
    错误原因:因为我是按顺序存入string,从后往前读取,容易存在越界;并且对进位处理如下:
for(int k=0;k<num-1;k++)
	{
		int j=num;
		for(int i=num-k;i>=1;i--,j--)
		{
			int x,y;
			x=a[i-1];
			y=ans[j];
			//cout<<x<<" "<<y<<" "<<x+y<<endl;
			if(x+y>=10)
			{
				int z=(x+y)%10,w=(x+y)/10;
				ans[j]=z;
				ans[j-1]+=w;//此处
			}
			else
			{
				ans[j]=x+y;
			}
		}
	}//用例通过率为 36%

若ans[j-1]+w的值也要进行进位处理,容易出错;但是当时样例没错,我没想到这个原因,最终这道题目也没有过。
正确代码

#include<bits/stdc++.h>
using namespace std;
string x;
string res;
int main()
{
	cin>>x;
	int s=0,c=0;
	for(int i=0;i<x.size();i++)
	{
		s+=x[i]-'0';
	}
	for(int i=x.size()-1;;i--)
	{
		c+=s;
		res.push_back('0'+(c%10));
		c/=10;
		if(i>=0)
		{
			s-=(x[i]-'0');
		}
		if(i<=0&&c==0)
		{
			break;
		}
	}
	reverse(res.begin(),res.end());
	cout<<res;
	return 0;
}

/*
num=4,
1234
1225
 122 1347
  12 1359
   1 1360
   */
  1. nn与游戏
    题意:给出了一个大小为n*n且有障碍的矩阵,然后给出了m对起点与终点,求起点到终点的最短距离;
    题解:图论,考察bfs,使用队列,对每个起点使用bfs;
    流程:
    ①将起点加入队列。
    ②弹出队首元素u。
    ③将u上下左右四个方向且满足条件(不是障碍,不是其他的起点或终点,之前没有访问过)的点加入队列,并更新距离。
    ④如果队列为空则退出,否则返回②。

这道题我应该可以做的,但是由于和上一道特征值死磕压根没看。。。下次再也不了。
代码

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int mp[N][N];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n,m;
int fx[11],fy[11];
int ex[11],ey[11];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=m;++i)
	{
		int x,y;
		cin>>x>>y;
		mp[x][y]=-1; 
	}
	int t;
	cin>>t;
	for(int i=1;i<=t;i++)
	{
		int x,y;
		cin>>x>>y;
		mp[x][y]=-1;
		fx[i]=x,fy[i]=y;
		cin>>x>>y;
		ex[i]=x,ey[i]=y;
		mp[x][y]=-1;
	}
	for(int i=1;i<=t;i++)
	{
		queue<pair<pair<int, int>, int> > q;
		q.push(make_pair(make_pair(fx[i],fy[i]), 0));
		int ans=0;
		while(q.size()&&ans==0)
		{
			int x=q.front().first.first,y=q.front().first.second,d=q.front().second;
			q.pop();
			for(int k=0;k<4;k++)
			{
				int xx=x+dx[k],yy=y+dy[k];
				if(xx==ex[i]&&yy==ey[i])
				{
					ans=1;
					cout<<d+1<<endl;
					break;
				}
				if(xx>=0&&xx<n&&yy>0&&yy<n&&mp[xx][yy]!=-1&&mp[xx][yy]<i)
				{
					mp[xx][yy]=i;
					q.push(make_pair(make_pair(xx,yy), d+1));
				}
			}
		}
		if(ans==0) cout<<-1<<endl;
	}
	return 0;
}
  1. 第二大数
    题意:给定一个有N个数的排列P,包含(1,2,…,N),其中给定任意一组(L,R)(1<=L<=R<=N), 定义XL,R为序列元素从下标L到R中第二大的数字。算出所有XL,R的和,其中L从1到N-1,R从L+1到N;
    取值范围:2<=N<=104 ; 如果只开int的话,用例通过率为 66.67%
    题解:假设我们已经知道(L,R)的答案,那么我们可以很容易知道(L,R+1)的答案,直接检测ar+1是否能更新最小值就行;如果ar+1次大值,次大值=ar+1;否则,ar+1最大值,次大值=最大值,最大值=ar+1
    代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll arr[10100];
int main()
{
    ll n,ans=0,first,second;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>arr[i];
    for(int i=1;i<n;i++)
    {
        first=max(arr[i],arr[i+1]);
        second=min(arr[i],arr[i+1]);
        ans+=second;
        //cout<<second<<" "<<i<<endl; 
        for(int j=i+2;j<=n;j++)
        {
            if(arr[j]>first)
            {
                second=first;
                first=arr[j];
            }
            else if(arr[j]>second)
            {
                second=arr[j];
            }
            ans+=second;
            //cout<<second<<" "<<i<<" "<<j<<endl;
        }
    }
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值