problem A:机器人
机器人Bo很聪明,会做许多事情。惟独对自然数的理解与人类不一样,它是从右往左读数。比如,它看到123时,会理解成321.让它比较23与15哪一个大,它说15大。原因是它的大脑会以为是32与51在进行比较.再比如让它比较29与30,它说29大。 当然对于像90,它会把它当成9处理。给定Bo N个自然数x,让它将这N个数按从小到大排序出来。你会认为它如何排序?
Input
第一行: N表示有多少个数. (2<=N<=25 )
接下来有N个数字x.( 0<=x<1e9 )
Output
对于每一行测试数据,输出一行,为所有排好序的元素,元素之间有一个空格.
#include <bits/stdc++.h>
using namespace std;
#include <algorithm>
struct stu{
string x;
int y;
}p[25];
bool cmp(stu a,stu b)
{
return a.y<b.y;
}
int main()
{
int n,i,j;
string s;/*sting字符串,需用cin cout 输入输出*/
while( cin>>n)
{
for(i=0;i<n;i++)
{
cin>>s;/*将数字用字符记录,便于反转*/
/*s.size()是数组s的长度,也可用strlen(s)表示*/
p[i].x=s;int sum=0;
for(j=s.size()-1;j>=0;j--)
{
sum=sum*10;
sum=sum+(s[j]-'0');/*s[j]都是数字字符减去字符0,能更好地比较*/
}
p[i].y=sum;
}
sort(p,p+n,cmp);
for(i=0;i<n-1;i++)
cout<<p[i].x<<" ";
cout<<p[n-1].x<<endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
#include <algorithm>
struct stu{
int x;
int y;
}p;
bool operator<(const stu &a1,const stu &b1)
{
return a1.y>b1.y;
}
priority_queue<stu,vector<stu> >vis;
int main()
{
int n,x,y,b,a[10];
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d",&x);p.x=x;
int t=0;
while(x>0)/*把数掉头的方法*/
{
t=t*10;
t=t+x%10;
x=x/10;
}
p.y=t;
vis.push(p);
}
while(vis.size()>1)
{
stu tmp=vis.top();
printf("%d ",tmp.x);
vis.pop();
}
printf("%d\n",vis.top().x);
vis.pop();
}
return 0;
}
problem B:纸牌游戏
小明闲来无事,看到了一堆纸牌(编号从1到N)放在了他的面前,他想到了一个好办法打发时间。他把第一张牌扔掉然后把新的第一张牌放入整叠纸牌的最后面。不断的重复操作,直到只剩一张牌,他想知道在这个过程中他扔了哪些纸牌,最后留下的是哪张纸牌。
Input
第1行输入T代表数据组数。(T<=50)
第2行到第1+T行输入纸牌的数量N(1<=N<=50)。
Output
第一行按顺序输出扔掉的纸牌。
第二行输出最后剩下的纸牌。
若没有扔掉的纸牌,则只输出剩下的纸牌
#include <bits/stdc++.h>
using namespace std;
#include <algorithm>
queue<int>vis;
int main()
{
int t,b[50];
scanf("%d",&t);
while(t--)
{
memset(b,0,sizeof(b));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
vis.push(i);
int ans=0;
while(vis.size()>1)
{
b[ans++]=vis.front();
vis.pop();
int a=vis.front();
vis.pop();
vis.push(a);
}
if(b[0]!=0)
{for(int i=0;i<ans-1;i++)
printf("%d,",b[i]);
printf("%d\n",b[ans-1]);
}
printf("%d\n",vis.front());
vis.pop();/*记得清空队列*/
}
return 0;
problem C:库特的合并果子
库特精心经营这他的果园,她已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。库特决定把所有的果子合成一堆。每一次合并,库特可以把两堆果子合并到一起,消耗的体力等于两堆果子的数量之和。可以看出,所有的果子经过 n-1 次合并之后, 就只剩下一堆了。库特当然希望她耗费的总体力最少,聪明的库特已经想到了一种最优方案解决这个问题了,那就是每一轮都将数量最少的两堆合并在一起,库特想知道按照她的方案每一轮消耗的体力值分别是多少,你能帮帮库特吗?
Input
多组输入
每组数据共两行。
第一行是一个整数 n(2≤n≤200000) ,表示果子的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数 ai(1≤ai ≤1000000) 是第 i 种果子的数目。
Output
一行n-1个整数,表示从第1轮到第n-1轮合并每一轮分别消耗的体力值,每相邻两个整数间输出一个空格。
Sample Input
4
3 4 5 6
Sample Output
7 11 18
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
priority_queue<ll,vector<ll>,greater<ll> >vis;
int main()
{
ll n,x;
while(scanf("%lld",&n)!=EOF)
{
for(ll i=1;i<=n;i++)
{
scanf("%lld",&x);
vis.push(x);
}
while(vis.size()>1)
{
ll tmp1=vis.top();
vis.pop();
ll tmp2=vis.top();
vis.pop();
if(vis.size()>=1) printf("%lld ",tmp1+tmp2);/*控制条件,最后一项不在循环中输出*/
vis.push(tmp1+tmp2);
}
printf("%lld\n",vis.top());/*最后一项单独输出*/
vis.pop();
}
return 0;
}
problem D:咸鱼连突刺
宇宙洪荒之时便现于世间,威名显赫的咸鱼家族有着代代相传的高超武技,其中最为咸鱼的,就是“咸鱼连突刺”,其技巧在于精准的控制伤害。咸鱼组长的变态训练方法是,每次攻击时给出两个数字 L 和 R ,新来的咸鱼蛋子们要精准的刺出L 和 R之间最大的素数与最小的素数之和的伤害值(如果之间没有素数,则相当于本回合造成的伤害值为0),两个素数可以是L或者R。而你要帮咸鱼组长计算这天所有的攻击一共打出了多少伤害。
Input
给出攻击次数T,1<=T<=1e4,接下来T行,每行给出两个数字L R 0<=L<=R<1e6。
Output
输出今天的伤害总值
Sample Input
1
1 10
Sample Output
9
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int prime[N];
int b[N];
int cnt=0;
int init(){
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=N-1;i++)
{
if(b[i])
prime[cnt++]=i;
for(int j=0;j<=cnt&&prime[j]*i<=N-1;j++)
{
b[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
return 0;
/*打出的素数表是从小到大排序的*/
}
int main()
{
int t,l,r,flag1,flag2;
long long sum=0;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&l,&r);/*用两个二分中学到的函数*/
flag1=lower_bound(prime,prime+cnt,l)-prime;/*输出第一个大于等于l的下标*/
flag2=upper_bound(prime,prime+cnt,r)-prime-1;/*输出第一个大于大于r的下标*/
if(flag1<cnt&&prime[flag1]>r||flag2>=0&&prime[flag2]<l)sum+=0;/*排除越界的情况,但是此法用到素数表的第一个元素需要prime从prime[0]开始*/
else sum+=prime[flag1]+prime[flag2];
}
printf("%lld\n",sum);
```
```c++
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int prime[N];
int b[N];
int cnt=0;
int init(){
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=N-1;i++)
{
if(b[i])
prime[cnt++]=i;
for(int j=0;j<=cnt&&prime[j]*i<=N-1;j++)
{
b[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
return 0;
/*打出的素数表是从小到大排序的*/
}
int main()
{
int t,l,r,flag1,flag2,a1,a2;
long long sum=0;
init();
scanf("%d",&t);
while(t--)
{
flag1=flag2=0;/*暴力的方法,因为素数不多,所以暴力会比较快*/
scanf("%d%d",&l,&r);
for(int i=l;i<=r;i++)
{
if(b[i])
{
flag1=1;a1=i;break;
}
}
for(int i=r;i>=l;i--)
{
if(b[i])
{
flag2=1;a2=i;break;
}
}
if(flag1&&flag2)
sum+=a1+a2;
}
printf("%lld\n",sum);
return 0;
problem E:库特的素数队列(1)
由于一个和库特很熟的幼儿园阿姨在某一天突然有急事,所以她拜托库特帮她讲一天的课,正好这天课程的内容是素数。由于大家还小,库特希望能够能以游戏的方式来给他们讲解。幼儿园共有n个孩子(n<=1e7),他们的序号分别是从1到n。库特让这n个孩子按照序号从小到大的顺序从左到右站成一排,然后从左向右依次报数,从第一个人开始,第一个人开始报1,之后每个人报的数字比他左边的人大1。最后报的数为素数的人能进入下一轮。然后进入下一轮的人再按序号从小到大的顺序从左到右站成一排,然后从左向右依次报数,从第一个人开始,第一个人开始报1,之后每个人报的数字比他左边的人大1,最后报的数为素数的人能进入下一轮…重复这个操作直至只剩下一个孩子。库特会给这个孩子奖励,请问你能知道序号为几的孩子能得到库特的奖励吗?
Input
第一行一个正整数T表示数据组数(T<=3)
接下来T行每行一个正整数n表示孩子的数量(n<=1e7)
Output
对于每组数据,输出一行,输出最后得到奖励的孩子的序号
Sample Input
2
2
6
Sample Output
2
5
#include <bits/stdc++.h>
#include <iostream>
const int N=1e7;
using namespace std;
int b[N+1];int prime[N+1];
int ans=0;
bool init()
{
memset(b,1,sizeof(b));
b[0]=b[1]=0;
for(int i=2;i<=N;i++)
{
if(b[i])
prime[ans++]=i;
for(int j=0;j<ans&&prime[j]*i<=N;j++)
{
b[prime[j]*i]=0;
if(i%prime[j]==0)break;
}
}
}
queue <int> vis;
int main()
{
int n,t,i;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
vis.push(i);
while(vis.size()!=1)
{
int q=vis.size();/*用q标记长度,因为长度是在变化的*/
for( i=1;i<=q;i++)
{
if (vis.size()==1)break;
int tmp=vis.front();
if(b[i])
vis.push(tmp);
vis.pop();
}
}
printf("%d\n",vis.front());
vis.pop();/*记得清空队列*/
}
return 0;
}
problem F:库特的素数队列(2)
由于一个和库特很熟的幼儿园阿姨在某一天突然有急事,所以她拜托库特帮她讲一天的课,正好这天课程的内容是素数。由于大家还小,库特希望能够能以游戏的方式来给他们讲解。幼儿园共有n个孩子(n<=1e7),他们的序号分别是从1到n。库特让这n个孩子按照序号从小到大的顺序从左到右站成一排,然后从左向右依次报数,从第一个人开始,第一个人开始报1,之后每个人报的数字比他左边的人大1。最后报的数为素数的人能进入下一轮。然后进入下一轮的人再按序号从小到大的顺序从左到右站成一排,然后从左向右依次报数,从第一个人开始,第一个人开始报1,之后每个人报的数字比他左边的人大1,最后报的数为素数的人能进入下一轮…重复这个操作直至只剩下一个孩子。库特会给这个孩子奖励,请问你能知道序号为几的孩子能得到库特的奖励吗?
Input
第一行一个正整数T表示数据组数(T<=30000)
接下来T行每行一个正整数n表示孩子的数量(n<=1e7)
Output
对于每组数据,输出一行,输出最后得到奖励的孩子的序号
Sample Input
2
2
6
Sample Output
2
5
#include <bits/stdc++.h>
#include <iostream>
/*通过E题打表测试可知答案范围*/
int a[12]={1,2,3,5,11,31,127,709,5381,52711,648391,9737333};
/*第一个答案成员是1,第二个2(弟一个素数),第三个3(第二个素数),第四个5(第三个素数),
第五个11(第五个),第六个31(第十一)*/
/*规律:后面一个数的答案是弟前一个答案(n)个素数,即弟n个素数*/
int main()
{
int t,n,i;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for( i=0;i<12;i++)
{
if(a[i]>n)break;
}
printf("%d\n",a[i-1]);
}
return 0;
}
problem G:库特的绳子
库特的屋子里有n个钉子,这n个钉子在一条直线上。我们可以把他们看成是数轴上的点,在位置x[i],每个钉子的位置各不相同。现在库特有m条绳子,库特想把所有的绳子都挂在这些钉子间(绳子能挂在两个钉子中间当且仅当两个钉子之间的距离小于等于绳子的长度),库特又不想把两个或以上绳子挂在相同的两个钉子对之间(也就是说任何两个钉子对之间最多只能挂一条绳子),请问库特最后能否将所有的绳子都挂在这些钉子间?
Input
第一行两个整数n和m(2<=n<=5e5,1<=m<=5e5)
第二行n个整数表示n个钉子所在的位置x[1]~xn
第三行m个整数表示m条绳子的长度a[1]~am
Output
如果能,输出yes
否则输出no
Sample Input
3 3
1 2 3
1 2 1
3 3
1 3 5
3 3 3
Sample Output
yes
no
#include <bits/stdc++.h>
using namespace std;
struct stu
{
int l,r,len;;
}tmp;/*队列和结构体连用时,结构体一般就一个变量tmp,因为是队列循环使用*/
bool operator < (const stu &p1,const stu &p2)
{
return p1.len>p2.len;
}
priority_queue <stu>q;
const int N=5e5+1;
int p[N];
int s[N];
int main()
{
int n,m,i;
while(scanf("%d %d",&n,&m)!=EOF)
{
while(!q.empty())q.pop();
for(i=0;i<n;i++)scanf("%d",&p[i]);
sort(p,p+n);
for(i=0;i<n-1;i++)
{
tmp.l=i;
tmp.r=i+1;
tmp.len=p[i+1]-p[i];
q.push(tmp);/*先把距离较短的钉压入队列*/
}
for(i=0;i<m;i++)scanf("%d",&s[i]);
sort(s,s+m);
for(i=0;i<m;i++)
{
if(q.empty())break;
tmp=q.top();
q.pop();/*取出第一对钉子*/
if(s[i]<tmp.len)break;
if(tmp.r+1<n)/*tmp.r<n-1表示当钉子还不是最后一个钉子*/
{
tmp.r++;
tmp.len=p[tmp.r]-p[tmp.l];/*扩大钉子间距,压入队列*/
q.push(tmp);/*队列不断输入输出,l也变,所有情况都能考虑到*/
}
}
if(i==m)printf("yes\n");/*i代表取出的钉子对数,m是绳子条数*/
else printf("no\n");
}
return 0;
}