题目
- 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;
}
- 题目“特征值”
题意:快速计算一个数字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
*/
- 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;
}
- 第二大数
题意:给定一个有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;
}