NOIP2016普及组初赛部分题解

问题求解1:

从一个 4×4 的棋盘(不可旋转)中选取不在同一行也不在同一列上的两个方格,共有____72_____种方法。
 

假设选择第一行,共有4个格子可以选择,然后从剩余的3行中进行选择,有4X3种可能。假设选择第2行,有3个格子可以选,有4X3X3种可能,第一个格子可能是4行中的任意一行,公共有4X3X3X4=144种可能,要排除重复(a,b),(b,a)这种情况,总共要除以2,所以最后有72种选择。

问题求解2

约定二叉树的根节点高度为1,一颗节点数为2016的二叉树最少有 ____1_____个叶子节点;一颗节点数为2016的二叉树最小的高度值为____11_____。

 

三、阅读程序写结果

1. 

#include
using namespace std;
int main()
{int max,min,sum,count = 0;int tmp;cin >> tmp;if(tmp == 0) return 0;max = min = sum = tmp;count ++;while(tmp!=0){cin >> tmp;if(tmp != 0){sum+=tmp;count++;if(tmp > max)max = tmp;if(tmp < min)min = tmp;//printf("%d %d %d %d\n",sum,count,max,min); }} cout << max <<"," << min <<","<< sum/count <

 输入:1 2 3 4 5 6 0 7

 答案: 6 1 3

这里其实输入到0后while就不执行了,就直接输出答案了,7不会再进行运算,不会输入进去。sum=1+2+3+4+5+6=21,

count=2+1+1+1+1=6

 

2. 

#include
using namespace std;
int main()
{int i = 100, x=0, y=0;while(i > 0){i--;x = i%8;if(x==1)y++;}cout << y << endl; return 0;} 

答案:13

相当于求解的100以内某个数除以8的余数为1的个数。

1

8*1+1   8*2+1  8*3+1  …… 8*12+1

共有13个数 

3.

#include
using namespace std;
int main()
{int a[6]={1,2,3,4,5,6};int pi = 0;int pj = 5;int t,i;while(pi < pj){t = a[pi];a[pi] = a[pj];a[pj] = t;pi++;pj--;}for(int i = 0; i < 6;i++)cout << a[i] <<",";cout << endl;return 0;} 

 答案:6,5,4,3,2,1,

这个代码实现的就是将数据倒序输出。

这里需要注意最后一个数也要有“,”号。还有缩进的问题,在for循环或者是while循环中,当只有一个语句的时候可以不打{},也就是说循环不打括号的时候,只有第一个语句在循环语句中。

#include
using namespace std;
int main()
{
    for(int i = 0; i < 4; ++i)
        cout << i << ",";
        cout << "hello";
    return 0;
 } 

#include
using namespace std;
int main()
{
    for(int i = 0; i < 4; ++i)
    {
        cout << i << ",";
    }
    cout << "hello";
    return 0;
 } 

等价。

 

 4.

#include
using namespace std;
int main()
{int i,length1,length2;string s1,s2;s1 ="I have a dream. ";s2 ="I Have a Dream. ";length1 = s1.size();length2 = s2.size();for(int i = 0; i < length1; i++){if(s1[i]>='a' && s1[i] <= 'z')s1[i]-='a'-'A'; }for(int i = 0; i < length1; i++){if(s2[i]>='a' && s2[i] <= 'z')s2[i]-='a'-'A'; }if(s1 == s2) cout << "=" << endl;else if(s1 > s2)cout << ">" << endl;elsecout << "<" << endl;return 0;} 

 答案:=

该代码实现的就是将字符串中的小写字母转换成大写字母,因此最终两个字符串都是“I HAVE A DRAEAM. "

 

四、完善程序

1.(读入整数)请完善下面的程序,使得程序能够读入两个int范围内的整数,并将这两个整数分别输出,每行一个。

输入的整数之间和前后只会出现空格或者回车。输入数据保证合法。

例如:

输入:

123

-789

输出:

123

-789

#include
using namespace std;
int readint(){int num = 0;//存储读取到的整数int negative = 0;//负数标识char c;//存储当前读取到的字符c = cin.get();while((c < '0' || c>'9') && c!='-')c = ____1____;if(c =='-')negative = 1;else______2____;c = cin.get();while(_____3____){______4____;c = cin.get();}if(negative == 1)_____5_____;return num;
}
int main()
{int a,b;a = readint();b = readint();cout << a << endl << b << endl;return 0;
}

 答案:

(1)cin.get()或者c=getchar()

(2) num = c-'0'或者num=c-48

(3)c >='0'&&c<='9'或者c>=48&&c<=57或isdigit(c)

(4)num = num*10+c-'0'或num=num*10+c-48

(5)num=-num或return -num

#include
using namespace std;
int readint(){int num = 0;int negative = 0;char c;c = cin.get();while((c < '0' || c>'9') && c!='-')//如果是非法读入,就不管它,继续读入 c = cin.get();if(c =='-')//如果读入的是负号,则标记负号,最后按照负数的格式输出 negative = 1;else//如果读入的不是负号,则将字符转成数字格式 num = c-'0';c = cin.get();while(c >= '0' && c <= '9')//如果读入的字符是0~9之间的数 {num = num*10 + c-'0';//将字符转成数字 c = cin.get();}if(negative == 1)//按照负数的格式输出 num = - num;return num;
}
int main()
{int a,b;a = readint();b = readint();cout << a << endl << b << endl;return 0;
}

 2.  ( 郊 游 活 动 ) 有 n 名 同 学 参 加 学 校 组 织 的 郊 游 活 动 , 己 知 学 校 给 这 n 名 同 学 的 郊 游 总 经 费 为 A 元 , 与 此 同 时 第 i 位 同 学 自 己 携 带 了 Mi 元 。 为 了 方 便 郊 游 , 活 动 地 点 提 供 B(>=n ) 辆 自 行 车 供 人 租 用 , 租 用 第 j 辆 自 行 车 的 价 格 为 Cj元 , 每 位 同 学 可 以 使 用 自 己 携 带 的 钱 或 者 学 校 的 郊 游 经 费 , 为 了 方 便 账 务 管 理 , 每 位 同 学 只 能 为 自 己 租 用 自 行 车 , 且 不 会 借 钱 给 他 人 , 他 们 想 知 道 最 多 有 多 少 位 同 学 能 够 租 用 到 自 行 车 。   

本 题 采 用 二 分 法 。 对 于 区 间 [l , r], 我 们 取 中 间 点 mid 并 判 断 租 用 到 自 行 车 的 人 数 能 否 达 到 mid, 判 断 的 过 程 是 利 用 贪 心 算 法 实 现 的 。

#include
using namespace std;
#define MAXN 1000000
int n,B,A,M[MAXN],C[MAXN],l,r,ans,mid;
bool check(int nn){int count = 0,i,j;i = ____(1)_____;j = 1;while(i <= n){if(___(2)_______)count += C[j]-M[i];i++;j++;}return ____(3)____; 
}void sort(int a[],int l, int r)
{int i=l,j = r,x = a[(l+r)/2],y;while(i <= j){while(a[i] < x) i++;while(a[j] > x) j--;if(i <= j){y = a[i];a[i]=a[j];a[j]=y;i++;j--;} }if(i < r) sort(a,i,r);if(l < j) sort(a,l,j);
}
int main()
{int i;cin >> n >> B >> A;for(i = 1; i <= n; i++)cin >> M[i];for(i = 1; i <= B; i++)cin >> C[i];sort(M,1,n);sort(C,1,B);l = 0;r = n;while(l <= r){mid = (l+r)/2;if(___(4)___){ans = mid;l = mid+1;}elser = __(5)____;}cout << ans << endl; return 0;} 

答案:

先将租用每辆自行车的价格和学生带的钱从小到大排序。

贪心策略:先匹配零花钱带的多的人,判断经费是否超过预算,如果没有超过预算则会有更多的学生可以租用自行车,如果超过了就减少租用自行车的人数。

#include
using namespace std;
#define MAXN 1000000
int n,B,A,M[MAXN],C[MAXN],l,r,ans,mid;
//n个人,B辆车,A总经费,M[i]第i位学生携带的钱,C[i]第i辆车租用的价格 
bool check(int nn){//判断nn个人租车钱是否超过了预算 int count = 0,i,j;i = n-nn+1;//i是排序后钱多的人 j = 1;while(i <= n){if(M[i] < C[j])//如果学生自己带的钱不够,就要用经费 count += C[j]-M[i];//花费的经费 i++;j++;}return count<=A; //花费的经费没超过预算就说明还有人可以租自行车 
}void sort(int a[],int l, int r)//从小到大排序 
{int i=l,j = r,x = a[(l+r)/2],y;while(i <= j){while(a[i] < x) i++;while(a[j] > x) j--;if(i <= j){y = a[i];a[i]=a[j];a[j]=y;i++;j--;} }if(i < r) sort(a,i,r);if(l < j) sort(a,l,j);
}
int main()
{int i;cin >> n >> B >> A;for(i = 1; i <= n; i++)cin >> M[i];for(i = 1; i <= B; i++)cin >> C[i];sort(M,1,n);sort(C,1,B);l = 0;r = n;while(l <= r){mid = (l+r)/2;if(check(mid))//如果没有超过经费,能租车的人数就比mid多 {ans = mid;l = mid+1;}elser = mid -1;}cout << ans << endl; return 0;} 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部