做这个题用了没多长时间就a了四道题,然后觉得我可以做出更多的时候突然发现别的都不太会了..到最后才拿到一个铜牌后来听说这些
都是2011年慈溪的小学奥赛题,瞬间心态崩了...这都大学了做小学题都这么费劲啊到头来,看来还得更努力才行啊~!下面开始咯~
问题 A: 录取分数线
题目描述
新学年,学校将成立信息学兴趣小组提高班。由于指导教师精力有限,只能以选拔考试的成绩为依据,按从高到低的分数,从N个参加选拔的学生中录取不超过M个成员。录取的成员要尽可能地多,但不得超过M个(含M个)。由于可能会有并列分数出现,为了保证公平,有时只得忍痛割爱,可能录取的成员会达不到计划数M。请你编程划定录取分数线。
输入
有N+1行,第一行是报名人数N和录取人数M。以下N行是考试成绩,已按从高到低的顺序排列。N、M和成绩均是1000以内的正整数,N≥M。数据保证不会所有的成绩都相同。
输出
只有1行,为录取分数线。
样例输入
复制样例数据 10 5
99
98
97
96
95
94
93
92
91
90
样例输出
95
这个题上来做的时候慌了,因为刚从厕所出来,很害怕我刚一点开就发现别的大佬都做了两道题 其实很简单 只需要
判断一下m-1的前一项和m-1项是否相等 如果相等的话就不能输出,代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[2000];
int main() {
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++) {
if(a[m-1]==a[m])
m--;//如果相等的话输出的时候
}
cout<<a[m-1];
}
问题 B: 电子警察
题目描述
现在很多地方的道路路口都安装了电子警察,即交通违章自动拍照系统。这些系统一般在路口的地下埋设感应线圈,通过传感器判断汽车是否在红灯时通过路面,来控制数码相机自动拍照。在安装这种系统需要挖掘地面,施工麻烦,成本又高。于是有人研究出了同摄像机自动识别车牌并判断违章行为的系统,这样一来,电子警察安装就方便多了,成本也大大降低。请你编程实现其中的一个功能,给出一批某一时间识别后的车牌号码及行进方向,判断该车是否违章,并记录下来。违章的规则设定为:先设置左转、直行、右转依次绿灯通行时间(以秒为单位,只允许一个方向绿灯),先左转绿灯,然后直行绿灯,最后右转绿灯,在其中一个绿灯时,其余两盏灯为红灯状态,假设时间生效在零时整,且给出的数据只限定当天。闯红灯为违章。
输入
第1行有4个整数,以一个空格隔开,依次为左转、直行、右转通行的绿灯持续秒数和识别的车辆数N(1≤N≤10000),后面的N行,表示每辆车的信息,格式为“时间+方向+车牌”,其中时间为6位数字,方向为1个字母(L表示左转,S表示直行,R表示右转),车牌为8个字符,之间没有空格。如081528LZJBB0001,表示车牌号为ZJBB0001的车辆在8时15分28秒左转。
输出
违章车辆的车牌号码,每辆车一行,不含空格,按输进去的先后顺序输出。
样例输入
复制样例数据 15 30 20 3
000046SZJBB8888
030950LJSAA9999
201509RBJC7777D
样例输出
ZJBB8888
BJC7777D
这道题目前我知道的有两种思路,第一种是将这些全部当做字符串,然后使用stringstream来处理一下这一行字符串,把h当做前两位
来计算,乘上3600,三四位为分钟,乘上60,56位是秒,乘上1或者不处理直接加上,然后对总共的时间取余(对整个周期),这里需
要注意的一点是代码中的e=(sum-1)%(l+s+r)+1;//这是队里马老板的写法,目的是抹去取模以后等于0的情况,可以自己手动模拟一
下。举个例子把 如果一个周期是65 然后这时候正好你前面输入的时间是65,这样按照通常的方法取余的话直接取到了0,而如果这样
操作一下,65-1等于64%65=64, 64+1又是65 正好分到了右拐的时间里,因为这时候是右拐的最后一秒,如果不这样处理,就直接分
分成了左拐的情况,这样就错了。 注意一下各个时间的区间: 左拐:(0,15] 直行:(15,45] 右拐(45,65] 就可以发现0和65是
不一样的,操作以后就不会出现那种65秒取余等于0归到左拐的情况了 代码实现:
(这是马老板的思想,不是我自己想的,先声明一下 这里是他的博客mhr博客
不过这是我手打的2333不是扒下来的
#include<bits/stdc++.h>
using namespace std;
int main() {
int l,s,r,n;
cin>>l>>s>>r>>n;
while (n--) {
string a;
cin>>a;
string h,m,c;
for(int i=0;i<2;i++)
h+=a[i];
for(int i=2;i<4;i++)
m+=a[i];
for(int i=4;i<6;i++)
c+=a[i];
stringstream a1,a2,a3;
a1<<h;
a2<<m;
a3<<c;
int h1,m1,c1;
a1>>h1;
a2>>m1;
a3>>c1;
int sum=h1*3600+m1*60+c1;
int dd;
int e=(sum-1)%(l+s+r)+1;//这是队里马老板的写法,目的是抹去取模以后等于0的情况,还有一种是if判断一下 一会提到
if(a[6]=='L') {
if(e>l) {
for(int i=7;i<a.size();i++)
cout<<a[i];
cout<<"\n";
continue;
}
}
else if(a[6]=='S') {
if(e<=l||e>s+l) {
for(int i=7;i<a.size();i++)
cout<<a[i];
cout<<"\n";
continue;
}
}
else if(a[6]=='R') {
if(e<=s+l) {
for(int i=7;i<a.size();i++)
cout<<a[i];
cout<<"\n";
continue;
}
}
}
}
这里还有第二种方法,是看了队里lk大佬的题解以后明白的,他的就比较的明了,直接判断等于0的情况,如果等于0直接判
断成左拐,没有问题,这种方法和上面的方法不一样,是先写出来哪样应该是正确的,然后给字符赋值正确的答案,判断字
符和正确答案是否一样,如果不一样就输出车牌号 我只能说...凯哥真狠啊 做题稳住狠
这种思路也不是我自己想的,先说明一下,是队里lk大佬的思路
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
char a[100];
int n,l,s,r;
cin>>l>>s>>r>>n;
while(n--) {
char k;
cin>>a;
int sum=((a[0]-'0')*10+a[1]-'0')*3600+((a[2]-'0')*10+a[3]-'0')*60+((a[4]-'0')*10+a[5]-'0');
if(sum==0)
k='L';
else {
sum%=(l+r+s);
if(sum>s+l)//这时候应该右拐
k='R';
else if(sum>l)//这时候应该直走
k='S';
else if(sum)//这时候的情况是左转的
k='L';
else k='R'; //这时候的情况是最后一秒或者取余为0的情况 上面已经有介绍为什么这里是右拐
}
if(k!=a[6]) {
for(int i=7;i<strlen(a);i++)
cout<<a[i];
cout<<endl;
}
}
}
问题 C: 查找特定的合数
题目描述
自然数中除了能被1和本身整除外,还能被其他数整除的数叫合数。每个合数都可以写成几个质数相乘的形式,这几个质数都叫做这个合数的质因数。比如8=2×2×2,2就是8的质因数。在1—N(N≤200000)按从小到大顺序排列的自然数序列中,查找第M个有X(2≤X≤6)个不同质因数的合数。例如,第3个有2个不同质因数的合数是12(12只有2、3两个不同的质因数,在12之前有2个不同质因数的合数分别为6和10)。
输入
共1行,分别为M,X。
输出
共1行,为第M个有X个不同质因数的合数。
样例输入
复制样例数据 3 2
样例输出
12
这题的思路是:先打出一个素数表,然后因为是计算合数被质因数组成,所以就从2到200000枚举一下,当枚举到的数字为质数的时候就先跳过,调用slove函数,从i=0对应的素数到枚举到的这个数(n)之间用这个合数除以对应的素数,如果能整数的话就说明可以分解成这个质因数乘以另一个质因数,或者只能被整除而已。ans1++之后结束for循环,把ans1返回到主函数,如果ans1的值和输入的x相等,就说明这个合数可以被分成x个质因数,sum++ 当sum==m的时候说明到了题目要求的第m个满足条件的合数,输出即可
代码:
打表程序
#include<bits/stdc++.h>
using namespace std;
bool is_prime(int num) {
for(int i=2;i*i<=num;i++) {
if(num%i==0)
return 0;
}
return 1;
}
int main() {
freopen("out.txt","w",stdout);
for(int i=2;i<=80000;i++)
if(is_prime(i))
cout<<i<<",";
}
刚开始昏迷了打表函数都写错了。。。现在是正确的了
#include<bits/stdc++.h>
using namespace std;
int prime[]={素数表};//由于打20w代码太长交不上去,打了8w以内的素数
bool is_prime(int num) {
for(int i=2;i*i<=num;i++) {
if(num%i==0)
return 0;
}
return 1;
}
int solve(int n) {
int ans=0;
for(int i=0;prime[i]<=n;i++) {
if(n%prime[i]==0) {
n/=prime[i];
ans++;
}
}
return ans;
}
int main() {
int m,x;
cin>>m>>x;
int sum=0;
int ans2=0;
for(int i=2;i<200000;i++) {
if(is_prime(i))
continue;
if(solve(i)==x)
sum++;
if(sum==m) {
ans2=i;
break;
}
}
cout<<ans2;
}
问题 D: 传话游戏
题目描述
有这样一个朋友网络,如果a认识b,那么a收到某个消息,就会把这个消息传给b,以及所有a认识的人。但是,请你注意,如果a认识b,b不一定认识a。现在我们把所有人从1到n编号,给出所有“认识”关系,问如果i发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了i(1≤i≤n)。
输入
第1行是两个数n(n<1000)和m(m<10000),两数之间有一个空格,表示人数和认识关系数。接下来的m行,每行两个数a和b,表示a认识b(1≤a,b≤n)。认识关系可能会重复给出,但1行的两个数不会相同。
输出
一共有n行,每行一个字符T或F。第i行如果是T,表示i发出一条新消息会传回给i;如果是F,表示i发出一条新消息不会传回给i。
样例输入
4 6
1 2
2 3
4 1
3 1
1 3
2 3
样例输出
T
T
T
F
本题使用了floyd算法,是求最短路的一种算法,定义如下:
在计算机科学中,Floyd-Warshall算法是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法。
算法的单个执行将找到所有顶点对之间的最短路径的长度(加权)。虽然它不返回路径本身的细节,
但是可以通过对算法的简单修改来重建路径。
该算法的版本也可用于查找关系R的传递闭包,或(与Schulze投票系统相关)在加权图中所有顶点对之间的最宽路径。
Floyd-Warshall算法是动态规划的一个例子,并在1962年由Robert Floyd以其当前公认的形式出版。
然而,它基本上与Bernard Roy在1959年先前发表的算法和1962年的Stephen Warshall中找到图形的传递闭包基本相同,
并且与Kleene的算法密切相关 在1956年)用于将确定性有限自动机转换为正则表达式。
算法作为三个嵌套for循环的现代公式首先由Peter Ingerman在1962年描述。
该算法也称为Floyd算法,Roy-Warshall算法,Roy-Floyd算法或WFI算法。 [2]
下面是核心思路通过一个图的权值矩阵求出它的每两点间的最短路径矩阵。 [3]
从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归地进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1);
又用同样地公式由D(1)构造出D(2);……;最后又用同样的公式由D(n-1)构造出矩阵D(n)。
矩阵D(n)的i行j列元素便是i号顶点到j号顶点的最短路径长度,称D(n)为图的距离矩阵,同时还可引入一个后继节点矩阵path来记录两点间的最短路径。
采用松弛技术(松弛操作),对在i和j之间的所有其他点进行一次松弛。所以时间复杂度为O(n^3);
状态转移方程
其状态转移方程如下: map[i,j]:=min{map[i,k]+map[k,j],map[i,j]};
map[i,j]表示i到j的最短距离,K是穷举i,j的断点,map[n,n]初值应该为0,或者按照题目意思来做。
当然,如果这条路没有通的话,还必须特殊处理,比如没有map[i,k]这条路。
算法过程:
1,从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
2,对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
把图用邻接矩阵G表示出来,如果从Vi到Vj有路可达,则G[i][j]=d,d表示该路的长度;否则G[i][j]=无穷大。
定义一个矩阵D用来记录所插入点的信息,D[i][j]表示从Vi到Vj需要经过的点,初始化D[i][j]=j。
把各个顶点插入图中,比较插点后的距离与原来的距离,G[i][j] = min( G[i][j], G[i][k]+G[k][j] ),
如果G[i][j]的值变小,则D[i][j]=k。在G中包含有两点之间最短道路的信息,而在D中则包含了最短通路径的信息。
比如,要寻找从V5到V1的路径。根据D,假如D(5,1)=3则说明从V5到V1经过V3,路径为{V5,V3,V1},如果D(5,3)=3,
说明V5与V3直接相连,如果D(3,1)=1,说明V3与V1直接相连。 [4]
百度的参考代码:
#include<iostream>
#include<vector>
using namespace std;
const int &INF=100000000;
void floyd(vector<vector<int> > &distmap,//可被更新的邻接矩阵,更新后不能确定原有边
vector<vector<int> > &path)//路径上到达该点的中转点
//福利:这个函数没有用除INF外的任何全局量,可以直接复制!
{
const int &NODE=distmap.size();//用邻接矩阵的大小传递顶点个数,减少参数传递
path.assign(NODE,vector<int>(NODE,-1));//初始化路径数组
for(int k=1; k!=NODE; ++k)//对于每一个中转点
for(int i=0; i!=NODE; ++i)//枚举源点
for(int j=0; j!=NODE; ++j)//枚举终点
if(distmap[i][j]>distmap[i][k]+distmap[k][j])//不满足三角不等式
{
distmap[i][j]=distmap[i][k]+distmap[k][j];//更新
path[i][j]=k;//记录路径
}
}
void print(const int &beg,const int &end,
const vector<vector<int> > &path)//传引用,避免拷贝,不占用内存空间
//也可以用栈结构先进后出的特性来代替函数递归
{
if(path[beg][end]>=0)
{
print(beg,path[beg][end],path);
print(path[beg][end],end,path);
}
else cout<<"->"<<end;
}
int main()
{
int n_num,e_num,beg,end;//含义见下
cout<<"(不处理负权回路)输入点数、边数:";
cin>>n_num>>e_num;
vector<vector<int> > path,
distmap(n_num,vector<int>(n_num,INF));//默认初始化邻接矩阵
for(int i=0,p,q; i!=e_num; ++i)
{
cout<<"输入第"<<i+1<<"条边的起点、终点、长度(100000000代表无穷大,不联通):";
cin>>p>>q;
cin>>distmap[p][q];
}
floyd(distmap,path);
cout<<"计算完毕,可以开始查询,请输入出发点和终点:";
cin>>beg>>end;
cout<<"最短距离为"<<distmap[beg][end]<<",打印路径:"<<beg;
print(beg,end,path);
}
了解了这个算法以后,贴上本题的代码,如果a和b有关系,b和c有关系,那么a与c就有关系,利用二维数组来存关系:
#include<bits/stdc++.h>
using namespace std;
int dfs[1000][1000];//定义全局变量并且赋值为0;
int main() {
int n,m,x,y;
cin>>n>>m;
while(m--) {
cin>>x>>y;
dfs[x][y]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++) {
if((dfs[j][i])&&(dfs[i][k]))
dfs[j][k]=1;
}
for(int i=1;i<=n;i++) {
if(dfs[i][i])
cout<<"T\n";
else
cout<<"F\n";
}
return 0;
}
问题 E: 谁是冠军
题目描述
小Q自从参加某小学计算机兴趣小组以来,对编程产生了浓厚的兴趣。他发现用计算机编程不但可以训练思维,还可以解决学习和生活中的一些实际问题。比如,世界杯足球赛时,小Q就经常把其中的一些球队列出来,组成一个小团队,然后根据规则计算积分,并根据积分的高低看看这个团队内谁是冠军。假如某次足球赛的积分规则如下:每胜一局得3分,每平一局得1分,每输一局扣1分,积分最高者为冠军。小Q就想编这样一个程序,输入若干球队的成绩,就能自动求出这个团队中谁是冠军。你也能编一个吗?
输入
输入有两行,第一行是输入的球队数,第二行是每队的比赛成绩,依次为球队编号、胜局数、平局数、负局数(均为小于1000的整数),每个数据间用一空格隔开。输入的数据保证积分各不相同。
输出
只有一个数,就是冠军队的编号。
样例输入
复制样例数据 4
1 5 4 3
2 3 4 5
3 6 3 3
4 4 2 6
样例输出
3
这题的难度算是偏简单 只需要开一个结构体,然后将和加起来排序,之后最大的输出即可:
#include<bits/stdc++.h>
using namespace std;
struct node {
int id;
int b;
int c;
int d;
int sum=0;
}e[2000];
bool cmp (node a,node b) {
return a.sum>b.sum;
}
int main() {
int n,f[2000];
cin>>n;
for(int i=0;i<n;i++) {
cin>>e[i].id>>e[i].b>>e[i].c>>e[i].d;
e[i].sum=e[i].b*3+e[i].c-e[i].d;
}
sort(e,e+n,cmp);
cout<<e[0].id;
}
问题 F: 搭积木的诀窍
小Q的编程技术在一次搭积木比赛中也成了秘密武器。原来,比赛的规则是这样的:给你N个小木块(全部为一样大小的正方体),快速搭成如下图规则的形状(下图为5层的规模),要求层数为最大限度。由于小Q编了个程序,只要输入小木块个数N,就可以马上求出最多可以搭几层,还剩几个,所以小Q每次都是一次成功,从不需要翻工,速度也就领先了。你会编小Q这样的程序吗?
输入
只有一个整数N,表示小木块的个数,已知1≤N≤30000。
输出
有两行整数,第一行是最多可以堆的层数,第二行是剩余的小木块数。
样例输入
复制样例数据 37
样例输出
5
2
这个题可以用数学公式来解决 我有个大佬同学说忘记了数学公式,于是用模拟做的,我觉得太强了…
代码:
注意 到最后的时候如果多减了一次的话n会变成负数,这次要加上上次减去的那一层,因为c也多加了1,所以要及时减去。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n,sum=0,c=0,a=1;
cin>>n;
while(n>=0) {
n-=(a*(a+1))/2;
a++;
c++;
}
if(n<0) {
n+=(a-1)*a/2;
c--;
}
cout<<c<<"\n"<<n;
}
问题 G: 卡布列克常数
题目描述
最近,小Q在数学兴趣课中了解了“卡布列克常数”。卡布列克是一位数学家,他在研究数字时发现:任意一个不是用完全相同数字组成的四位数,如果对它们的每位数字重新排序,组成一个最大的数和一个最小的数,然后用最大数减去最小数,差不够四位数时补零,类推下去,最后将变成一个固定的数:6174,这就是卡布列克常数。
例如:4321-1234=3087
8730-378=8352
8532-2358=6174
7641-1467=6174
……
小Q想,我能不能编程来验证呢?输入一个符合条件的四位数,然后验证运算过程。
输入
共1行,为任意一个不是用完全相同数字组成的四位数。
输出
变为卡布列克常数的运算过程,由若干行组成,每行是一个算式,不含空格。
样例输入
复制样例数据 4321
样例输出
4321-1234=3087
8730-378=8352
8532-2358=6174
这题第一眼看上去我觉得用字符串写比较方便 但是写着写着发现每一次找最小和最大的数都很麻烦,而且
如果最后一位有0的话就非常的麻烦 ,于是最终决定定义两个函数,找到最大值最小值,返回以后再让他们
相减,等于答案的时候就退出循环。
代码:
#include<bits/stdc++.h>
using namespace std;
bool cmp(int a,int b) {
return a>b;
}
int maxn(int x) {
int a[4];
for(int i=3;x>0;i--) {
a[i]=x%10;
x/=10;
}
sort(a,a+4,cmp);
return a[0]*1000+a[1]*100+a[2]*10+a[3];
}
int minn(int x) {
int a[4];
for(int i=3;x>0;i--) {
a[i]=x%10;
x/=10;
}
sort(a,a+4);
return a[0]*1000+a[1]*100+a[2]*10+a[3];
}
int main() {
int n,sum;
cin>>n;
while(n!=6174) {
cout<<maxn(n)<<"-"<<minn(n)<<"="<<maxn(n)-minn(n);
n=maxn(n)-minn(n);
cout<<endl;
}
}
问题 H: 扫雷游戏
题目描述
小Q空的时候挺喜欢玩玩电脑游戏的。自从编程技术提高后,他就想,要是自己也能开发出一款游戏来,那该多好啊!不过,小Q也不着急,先练好基本功再说。Windows中就有一款叫扫雷的小游戏,挺好玩的,不过想编出一个来,还真不容易。小Q就自己设想了一种简单的扫雷游戏:在n行2列的方格棋盘上,左列某些方格内埋有地雷,而右列每个方格中都有一个数字(0~3),第I格的数字表示:左列第I-1、I、I+1格(即:上、中、下三格)中埋雷的总数。如下所示:左图是初始状态,右图是扫雷完成状态(插小旗的方格内有雷)。
你的任务是:根据右列的数字分析出左列格子中的地雷(0表示无雷,1表示有雷),并且统计出左列格子中地雷的总数。
小Q想,如果这样的任务能完成了,相信编出更复杂的扫雷游戏也就为期不远了。
输入
第一行,一个整数N(2≤N≤40),第二行有N个数字(以一个空格相隔),表示右列格子中的数字。输入数据保证正确有解。
输出
第一行是N个0、1数字(没有空格相隔),表示左列每格中有无地雷。第二行一个整数,表示地雷总数。
样例输入
复制样例数据 7
1 2 3 2 2 2 2
样例输出
0111011
5
这题看了博哥的题解以后明白了一些,因为第二行只有0 1 2 3 最大是3 所以可以通过规律一步一步找到下一个格子中左边的雷的个数(本题只需要找出左边有或者没有雷即可,所以可以通过规律一步一步往下推)不过需要注意的是:必须判断一下第一个格子里面是否有雷,这时候可以利用一下右边那一格中的数字来判断,然后先判断有雷的情况(其实我觉得先判断没有雷的情况也可以)刚开始如果没有雷的话就直接f=1 执行下面if(f==1)之后的语句,如果先判断第一个格子有雷的话,可以先走一次上面的for循环,**i从1开始,用j的for循环找出从i-1那一项到第i项的雷的个数,**如果推出矛盾,即代码中的
else if(a[i][1]>cnt+1)
矛盾的意思是:即使此时的雷总数加上下面那一格的雷都比此时输入的雷少,而右边的一列除了第一行对应两个左边的雷格子,其他的都是对应三个格子,矛盾之后说明第一个格子有雷不合理,于是就再次走下面的第一个格子没有雷的情况,最后i输出一下就行了 代码:
#include<bits/stdc++.h>
using namespace std;
int cnt;
int a[50][2];
int f=0;
int main( ) {
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i][1];
if(a[0][1]==0)
f=1;//如果第一个格子没有雷的话
else {//如果第一个格子有雷的话
a[0][0]=1;
if(a[0][1]==2)
a[1][0]=1;
else
a[1][0]=0;
}
for(int i=1;i<=n-1;i++) {
cnt=0;
for(int j=i-1;j<=i;j++)
if(a[j][0]==1)
cnt++;
if(a[i][1]-cnt==1)
a[i+1][0]=1;
else if(a[i][1]>cnt+1) {//第一个格子有雷推出有矛盾
for(int k=0;k<n;k++)//说明第一个格子没有雷 初始化雷表,再来一次循环?
a[k][0]=0;
f=1;
break;
}
}
if(f) {//此时第一个格子没有雷,判断第二个格子是否有雷
a[0][0]=0;
if(a[0][1]==1)
a[1][0]=1;
else
a[1][0]=0;
for(int i=1;i<=n-1;i++) {
cnt=0;
for(int j=i-1;j<=i;j++)
if(a[j][0])
cnt++;
if(a[i][1]-cnt==1)
a[i+1][0]=1;
else
a[i+1][0]=0;
}
}
int ans2=0;
for(int i=0;i<n;i++) {
if(a[i][0])
ans2++;//计数
cout<<a[i][0];
}
cout<<endl;
cout<<ans2;//输出
}