来吧,我来渡劫了!(等下,这句话划掉)
第一题:珠心算测验
题意简述:随机生成一个正整数集合,集合中的数各不相同,然后要求学生回答:其中有多少个数,恰好等于集合中另外两个(不同的)数之和?
陷阱提示:要注意必须得不同的数,如果相同没必要记两次
数据范围: 3≤n≤100 ,测验中每个数不大于10000
我对它的类型评估:模拟
思路描述:每一次读入数字时,将这个数字的存在设置为true,然后进行一次for循环,找有没有两个数可以加在一起等于第三个数且第三个数存在,如果有,计数,且将第三个数设置为不存在。
我的代码:
#include <cstdio>
int main(){
int math[100001];
bool r[100001];
int i,j,n,m,count=0;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&math[i]);
r[math[i]] = true;
}
for(i=0;i<n-1;i++){
for(j=i+1;j<n;j++){
if(r[math[i]+math[j]]){
count++;
r[math[i]+math[j]] = false;
}
}
}
printf("%d",count);
}
洛谷原题:http://www.luogu.org/problem/show?pid=2141
第一题完
第二题:比例化简
题意简述:给定一个比例A/B,以及一个上限l,使得在A’和B’均不大于L且A’和B’互质(两个整数的最大公约数是1)的前提下,
A′:B′≥A:B
且
A′:B′−A:B
的值最小。
陷阱提示:这一道题的输入输出均用标准输入输出流(cin,cout),用scanf以及printf会炸掉
数据范围: 1≤A≤1,000,000 , 1≤B≤1,000,000 , 1≤L≤100 , A/B≤L 。
我对它的类型评估:数论,模拟
思路描述:因为数据范围很小(L),所以这一道题暴力(即 O(n2) )可过。那么枚举两个数i,j。如果i/j小于当前的最小比例,就更新。并且必须使得i/j大于a/b。
我的代码:
#include <cstdio>
#include <iostream>
int main(){
double a,b,lower = 10000000,a_,b_,mid,n;
std::cin>>a>>b>>n;
mid = a/b;
for(double i=1.0;i<=n;i++){
for(double j=1.0;j<=n;j++){
if(i/j >= mid && i/j <lower-0.000000001){
a_=i;b_=j;
lower = i/j;
//printf("%f,%f\n",a_,b_);
}
}
}
std::cout<<a_<<" "<<b_;
}
洛谷原题:http://www.luogu.org/problem/show?pid=2118
第二题完
第三题:螺旋矩阵
题意简述:
一个n行n列的螺旋矩阵可由如下方法生成:
从矩阵的左上角(第1行第1列)出发,初始时向右移动;如果前方是未曾经过的格子,则继续前进,否则右转;重复上述操作直至经过矩阵中所有格子。根据经过顺序,在格子中依次填入1, 2, 3, … , n,便构成了一个螺旋矩阵。给定i,j,求第i行第j列的数字。
如下,就是一个螺旋矩阵:
陷阱提示:以这道题的数据范围来看,如果制作一个螺旋矩阵再找,会TLE!
数据范围:对于100%的数据, 1≤n≤30,000 , 1≤i≤n , 1≤j≤n。
我的思路:这道题要用几个数学规律来做。我们设a[p][q]为矩阵的第p行第q列。那么我们要求出i,j的位置,就先求出它们在第n层,然后再将该层的第一个数m求出,最后计算a[i][j]是这一层的第k个数。
最后的答案就是m+k。
我的代码:
#include <cstdio>
#include <cstring>
int n;
#define min(a,b) a<b?a:b
int GetFloor(int i,int j){
int a,b;
a = min(i,n-i+1);
b = min(j,n-j+1);
return a<b?a:b;
}
int Get_First_Number(int a){
int count=0,p=1;
for(int i=1;i<a;i++){
count+=(n-p)*4;
p+=2;
}
return count;
}
int Get_Number_Of_I_And_J(int i,int j,int k){
int a = n;
for(int l=1;l<k;l++){
a-=2;
}
if(i==1) return j;
if(j==a) return a+i-1;
if(i==a) return 3*a-j-1;
else return (a-1)*4-i+2;
}
int main(){
int i,j;
scanf("%d%d%d",&n,&i,&j);
int floor = (i,j);
int first = Get_First_Number(floor);
int answer = Get_Number_Of_I_And_J(i-floor+1,j-floor+1,floor);
printf("%d",answer+first);
}
特殊的地方:
我在玩题解的时候,看见了一个不符合常理的想法,我直接复制上来:
经计算可得
p为(x,y)所在圈的边长
n∗n−p∗p
为圈外数的个数
若x>y则(x,y)在圈的下或者左边,否则在上或右边。
如果在上或右边,
(x−(n−p)/2)+(y−(n−p)/2)−1=x+y−n+p−1
就是(x,y)所在圈的排名如果在下或左边,
(2p−(x−(n−p)/2))+(2p−(y−(n−p)/2))−1=3p−x−y+n−1
就是(x,y)所在圈的排名
所在圈排名加上圈外数的个数即为所求
他的代码:
#include <cstdio>
#define abs(x) (x<0?-(x):x)
#define max(x,y) (x>y?x:y)
int n,x,y,p;
int main()
{
scanf("%d%d%d",&n,&x,&y);
p=max(abs(n-(x<<1)+1),abs(n-(y<<1)+1))+1;
printf("%d\n",x>y?(n-p)*(n+p+1)+(p<<2)-x-y-1:(n-p)*(n+p-1)+x+y-1);
return 0;
很短啊有木有!
洛谷原题:http://www.luogu.org/problem/show?pid=2239
第三题完
对不起,第四题我实在无能为力
抱歉。