周周小训练1

101特殊的正方形


输入𝑛,输出𝑛𝑛列的由+和.组成的正方形,其中最外面一圈全是+,第二圈全是.,...,对于第𝑖圈,如果𝑖是奇数,那么全是+,否则全是.。

输入格式

一行,一个整数𝑛

输出格式

𝑛行,为满足题目要求的正方形。注意不要有行末空格。

样例输入

10

样例输出

++++++++++

+........+

+.++++++.+

+.+....+.+

+.+.++.+.+

+.+.++.+.+

+.+....+.+

+.++++++.+

+........+

++++++++++

数据范围

对于100%的数据,保证2≤𝑛≤100。

解题思路:

这道题就是一个简单的模拟,照着题意就行

用一个二维数组tu存图,一个二维数组tuu来判断此位置是否已经有点

用一个循环,一圈一圈判断:1对于奇数圈,将此奇数行和此奇数行的对行填入“+”,对列进行相同操作

2对于偶数圈,将此偶数行和此偶数行的对行填入“-”,对列进行相同操作

对已经存入的点要用tuu来记录

完整代码如下:

#include <bits/stdc++.h>

usingnamespacestd;

chartu[101][101];

booltuu[101][101];

intmain()

{

intn;

cin>>n;

for(inti=1; i<=n; i++){

for(intj=1; j<=n; j++){

tuu[i][j]=false;

}

}

intk=1;

while(k<=n){

if(k%2!=0){

for(inti=k; i<=n-k+1; i++){

if(!tuu[k][i]) tu[k][i]='+';

if(!tuu[n-k+1][i]) tu[n-k+1][i]='+';

tuu[k][i]=true;

tuu[n-k+1][i]=true;

}//对行进行处理

for(inti=k; i<=n-k+1; i++){

if(!tuu[i][k]) tu[i][k]='+';

if(!tuu[i][n-k+1]) tu[i][n-k+1]='+';

tuu[i][k]=true;

tuu[i][n-k+1]=true;

}//对列进行处理

}else{

for(inti=k; i<=n-k+1; i++){

if(!tuu[k][i]) tu[k][i]='.';

if(!tuu[n-k+1][i]) tu[n-k+1][i]='.';

tuu[k][i]=true;

tuu[n-k+1][i]=true;

}//对行进行处理

for(inti=k; i<=n-k+1; i++){

if(!tuu[i][k]) tu[i][k]='.';

if(!tuu[i][n-k+1]) tu[i][n-k+1]='.';

tuu[i][k]=true;

tuu[i][n-k+1]=true;

}//对列进行处理

}

k++;

}

for(inti=1; i<=n; i++){

for(intj=1; j<=n; j++){

cout<<tu[i][j];

}

cout<<endl;

}

return0;

}

102走楼梯2


楼梯有 𝑛 阶,上楼可以一步上一阶,也可以一步上二阶。

但你不能连续三步都走两阶,计算走到第𝑛阶共有多少种不同的走法。

输入格式

一行,一个数字,表示𝑛

输出格式

输出走楼梯的方式总数。

样例输入

6

样例输出

12

数据规模

对于100%的数据,保证𝑛≤50。

解题思路:

用dp

用f [i] [j] ,其中i表示一共走的台阶数,j表示已经连续走了几次两阶,f [i] [j] 表示走到此状态一共有几种走法

对于每一次状态,1.可以走一阶 f [i+1] [0] += f [i] [j]

2.可以走两阶 f [i+2] [j+1] += f [i] [j]

完整代码如下:

#include <bits/stdc++.h>

usingnamespacestd;

longlongf[55][3];

intmain()

{

intn;

cin>>n;

f[0][0]=1;

for(inti=0; i<=n; i++){

for(intj=0; j<=2; j++){

f[i+1][0]+=f[i][j];

if(j<2)f[i+2][j+1]+=f[i][j];

}

}

cout<<f[n][0]+f[n][1]+f[n][2];

return0;

}

103走路


有一条很长的数轴,一开始你在00的位置。接下来你要走𝑛步,第𝑖步你可以往右走𝑎**𝑖或者𝑏**𝑖

𝑛步之后,00到𝑚的每个位置,能不能走到?

输入格式

第一行,两个整数𝑛,𝑚

接下来𝑛行,每行两个整数𝑎**𝑖,𝑏**𝑖

输出格式

一行,一共𝑚+1个数,每个数都是0或1表示能否走到,数字之间不用空格隔开。

输入样例

3 10

1 2

2 6

3 3

输出样例

00000011001

数据规模

对于所有数据,保证1≤𝑛≤100,1≤𝑚≤10^5,1≤𝑎**𝑖,𝑏**𝑖≤1000。

解题思路:

dp

f [i] [j] 表示此路是否能通,i表示一共走的次数,j表示走到的位置

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=1e5+5;

int f[1005][maxn];

int n,m,a,b;

int main()

{

cin>>n>>m;

f[0][0]=1;

for(int i=1; i<=n; i++){

cin>>a>>b;

for(int j=0; j<=m; j++){

//前一个位置走到了,后一个位置能走到

if(f[i-1][j]==1 && j+a<=m) f[i][j+a]=f[i-1][j];

if(f[i-1][j]==1 && j+b<=m) f[i][j+b]=f[i-1][j];

}

}

for(int i=0; i<=m; i++) cout<<f[n][i];

return 0;

}

104简单分数统计


𝑁 个好朋友在codeforces上参加一场包含 𝑀 个题目的比赛, 比赛期间codeforces网站一共有 𝑘 次提交。

已知每个题目的分数,

但是由于他们只能查到在比赛期间codeforces总共的提交记录(其他用户提交的其他题目记录也包含在内, 即存在不属于该场比赛的题目),

所以想请你编写一个程序算出他们每个人的分数。

输入格式

第一行三个整数 𝑁, 𝑀, 𝐾 分别表示好朋友的个数, 题目的个数, 和提交的总次数(其中0<𝑁,𝑀,𝐾<=200)。

接下来 𝑁 行 第 𝑖 行输入为第 𝑖 个人的id,

接下来 𝑀 行 第 𝑗 行输入为第 𝑗 个题目的名称和分数,

接下来 𝐾 行 第 𝑘 行输入为第 𝑘 次提交的提交者id, 题目名称和结果("WA" 或 "AC", 如果"AC"代表通过这个题目, 提交者获得对应分数)。

注: 题目名称和id均为仅包含英文字母和数字的字符串, 题目分数为小于等于 1𝑒61�6 的正整数. 每一行的多个输入之间用空格隔开。

所有输入的字符串长度 𝑙𝑒𝑛𝑔𝑡**ℎ 满足 0<𝑙𝑒𝑛𝑔𝑡**ℎ≤500。

所有用户id和题目名称不存在重名, 用户AC了某个题之后之后不会再重复提交该题, 好朋友们只会提交属于比赛的题目。

输出格式

输出 𝑁 行, 第 𝑖 行输出第 *𝑖 *个人的名字和对应分数 (名字和分数用空格隔开)。

样例输入

2 2 4

GabrielPessoa

beza

metebronca 100

geometry 200

beza metebronca AC

ffern numbertheory AC

GabrielPessoa geometry WA

beza geometry AC

样例输出

GabrielPessoa 0

beza 300

样例解释

beza 过了 metebronca和geometry 拿到 300300 分。

GabrielPessos 没有过题, 所以是 00 分。

还有一些其他选手提交的其他题目忽略不计。

解题思路:

模拟

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=1e4+5;

int n,m,k;

struct stu{

string name;

int sum;

}student[maxn];//表示用户的id和最终成绩

struct pro{

string question;

int score;

}prom[maxn];//表示问题的名称和对应分数

int main()

{

cin>>n>>m>>k;

for(int i=1; i<=n; i++) cin>>student[i].name;

for(int i=1; i<=m; i++) cin>>prom[i].question>>prom[i].score;

string a,b,c;

while(k--){

cin>>a>>b>>c;//a,b,c分别表示提交者id, 题目名称和结果

for(int i=1; i<=n; i++){

if(student[i].name==a && c[0]=='A'){

for(int j=1; j<=m; j++){

if(prom[j].question==b) student[i].sum+=prom[j].score;

}

}

}

}

for(int i=1; i<=n; i++) cout<<student[i].name<<" "<<student[i].sum<<endl;

return 0;

}

Alice的德州扑克


德州扑克是目前世界上最流行的扑克游戏,全世界有众多相关的比赛,例如是 WSOP,WPT,EPT等,也让这款游戏的玩法变得层出不穷,丰富多变。 不要被简单的游戏规则而误导,复杂多变的比赛状况,让这款游戏在高水平的竞技中会变得非常复杂,这也让人们为德州扑克给出了这样一句评价 ”用一刻就能学会,但要用一生才能掌握” 。

现在我们并不在乎游戏规则是什么,因为 Alice 是一个德州扑克高手,他对于德州扑克的规则烂熟于心,不过他每次都记不得牌型的大小关系,他知道你是一个编程高手,所以他想让你帮他写一个程序:输入五张牌的大小和花色,输出这五张牌能组成的最大牌型.你能帮帮他吗?

为了降低你的编程难度,我们规定:

  1. 输入的牌都是来源于同一副扑克牌

  1. 输入的牌的点数都是非递减的

  1. 所有花色没有大小之分

下面给出各牌型,(从大到小)

  1. 皇家同花顺(ROYAL FLUSH):五张顺连的牌(点数连续单调递增),且最大的一张牌是A(Ace),并且五张牌的花色相同

  1. 同花顺(STRAIGHT FLUSH):五张顺连的牌(点数连续单调递增),不规定最大的一张牌是A(Ace),并且五张牌的花色相同

  1. 四条(FOUR OF A KIND):至少四张牌的点数相同

  1. 葫芦(FULL HOUSE):至少三张牌的点数相同,并且除此之外还有两张牌的点数相同

  1. 同花(FLUSH):五张牌的花色都相同

  1. 顺子(STRAIGHT):五张顺连的牌(点数连续单调递增),不要求五张牌的花色相同

  1. 特别注意:由于 Alice 是个谨慎的人,所以比 三条(THREE OF A KIND) (包括三条) 小的牌型 Alice 不在乎他们的大小关系,你只需要告诉 Alice 弃牌就行

输入格式

输入两行,每行五个数字,第一行的第 𝑖 个字符表示第 𝑖 张扑克的点数,

第二行的第 𝑖 个数字表示第 𝑖 张扑克花色。(保证输入的牌的点数是非递减的,且所有输入均合法)

点数和对应输入的数字:

  • 2−102−10 对应 2 - 10

  • 𝐽(𝐽𝑎𝑐𝑘)对应 11

  • 𝑄(𝑄𝑢𝑒𝑒𝑛) 对应 12

  • 𝐾(𝐾𝑖𝑛𝑔) 对应 13

  • 𝐴(𝐴𝑐𝑒) 对应 14

花色和对应输入的数字:

  • 黑桃 (Spades) 对应 1

  • 方片 (Diamonds) 对应 2

  • 红桃 (Hearts) 对应 3

  • 梅花 (Clubs) 对应 4

输出格式

输出这五张牌能组成的最大牌型。

  • 如果最大是皇家同花顺输出 "ROYAL FLUSH"

  • 如果最大是同花顺输出 "STRAIGHT FLUSH"

  • 如果最大是四条输出 "FOUR OF A KIND"

  • 如果最大是葫芦输出 "FULL HOUSE"

  • 如果最大是同花输出 "FLUSH"

  • 如果最大是顺子输出 "STRAIGHT"

  • 如果最大的牌型小于等于三条输出"FOLD",劝 Alice 弃牌

  • 输出不包括引号

样例输入1

10 11 12 13 14

1 1 1 1 1

样例输出1

ROYAL FLUSH

样例输入2

10 11 12 13 14

1 2 1 3 4

样例输出2

STRAIGHT

样例输入3

6 6 6 7 7

1 2 3 1 3

样例输出3

FULL HOUSE

样例输入4

3 3 6 6 9

1 2 1 2 1

样例输出4

FOLD

解题思路:

模拟

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=1e5+5;

struct pai{

int point;

int color;

}p[maxn];//表示牌的点数和花色

int main()

{

for(int i=1; i<=5; i++) cin>>p[i].point;

for(int i=1; i<=5; i++) cin>>p[i].color;

int flag,cnt1=1,cnt2=1,cnt3=1,cnt4=1;

for(int i=2; i<=5; i++){

if(p[1].point==p[i].point) cnt1++;

}

for(int i=1; i<=4; i++){

if(p[5].point==p[i].point) cnt2++;

}//用来判断四条

for(int i=2; i<=3; i++){

if(p[1].point==p[i].point) cnt3++;

}

for(int i=4; i<=5; i++){

if(p[3].point==p[i].point) cnt4++;

}//用来判断葫芦

if(p[5].point-p[4].point==1 && p[4].point-p[3].point==1 && p[4].point-p[3].point==1 && p[3].point-p[2].point==1 && p[2].point-p[1].point==1 && p[1].color==p[2].color && p[2].color==p[3].color && p[3].color==p[4].color && p[4].color==p[5].color){

if(p[5].point==14) flag=1;//ROYAL FLUSH

else flag=2;//STRAIGHT FLUSH

}else if(cnt1>=4 || cnt2>=4) flag=3;//FULL HOUSE

else if(cnt3==3 && p[4].point==p[5].point || cnt4==3 && p[1].point==p[2].point) flag=4;//STRAIGHT

else if(p[1].color==p[2].color && p[2].color==p[3].color && p[3].color==p[4].color && p[4].color==p[5].color) flag=5;//FLUSH

else if(p[5].point-p[4].point==1 && p[4].point-p[3].point==1 && p[4].point-p[3].point==1 && p[3].point-p[2].point==1 && p[2].point-p[1].point==1) flag=6;//FOUR OF A KIND

else flag=0;

if(flag==1) cout<<"ROYAL FLUSH";

else if(flag==2) cout<<"STRAIGHT FLUSH";

else if(flag==3) cout<<"FOUR OF A KIND";

else if(flag==4) cout<<"FULL HOUSE";

else if(flag==5) cout<<"FLUSH";

else if(flag==6) cout<<"STRAIGHT";

else if(flag==0) cout<<"FOLD";

return 0;

}

订单编号


小缘开了一家公司,生意很好,每天都会收到很多订单,自动交易系统会自动给这些订单生成没有重复的订单编号。但是有一天,系统出现了未知的错误,导致当天的订单编号可能有重复的,这可把小缘急坏了。你可以帮助小缘按照规则给这些订单重新编号吗?

按照时间先后顺序给出 𝑁 个正整数作为原订单编号,你需要按照规则依次赋予这些订单新的编号,对于任意一个订单,要找到大于等于其原订单编号且未被使用过的(没有被之前的订单作为新的订单编号)的最小整数,作为它的新订单编号。

例如: 原订单编号依次为1 2 3 1,则新订单编号应该为1 2 3 4 (前3个订单的原订单编号都没有使用过,所以用其原订单编号即可,对于第四个订单,原订单编号为1,而1, 2, 3都已经被使用过,所以新订单编号为4)。

输入格式

第一行输入一个整数 𝑁 (1≤𝑁≤5×105)。

第二行输入 𝑁 个数 𝑎**𝑖 (1≤𝑎**𝑖≤109) 作为原订单编号。

输出格式

输出一行,包含 𝑁 个整数为新的订单编号。

样例输入1

6

2 3 4 1 1 1

样例输出1

2 3 4 1 5 6

样例输入2

3

1000000000 1000000000 1000000000

样例输出2

1000000000 1000000001 1000000002

样例输入3

6

4 5 1 2 1 1

样例输出3

4 5 1 2 3 6

解题思路:

本蒟蒻看了大佬的思路(qwq)

此题可以用set容器,set可以将元素从小到大自动排序,并且每个元素都是唯一的

一开始建立一个c区间,区间中的元素都没有被使用过

然后开始依次插入x,1当x在这个区间里时,把这个区间分成两个区间,并删去x

2当x在这个区间外时,就删去比x大的区间的左端点

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

set< pair<int,int> > c;

inline void insert(int l,int r){

if(l>r) return;

c.insert(make_pair(r,l));

}

int main()

{

int n,x;

scanf("%d",&n);

c.insert(make_pair(2e9,1));//r,l

for(int i=1; i<=n; i++){

scanf("%d",&x);

auto itr=c.lower_bound(make_pair(x,0)); //返回一个在c里面第一个大于等于(x,0)的元素,指向其迭代器(可以看成指针)

if(itr->second<=x){ //x在区间里面

printf("%d ",x);

insert(itr->second,x-1);

insert(x+1,itr->first);

c.erase(itr);

}else{ //x在区间外面

printf("%d ",itr->second);

insert(itr->second+1,itr->first);

c.erase(itr);

}

}

return 0;

}

饿饿 饭饭


𝑛个同学正在排队打饭,第𝑖个同学排在从前往后第𝑖个位置。但是这天食堂内只有一个食堂阿姨,为了使同学们都能尽快的吃上饭,每一个同学在打完一份饭之后就会排在队伍的末尾先吃着打到的饭,我们知道第𝑖个同学的饭量为𝑎**𝑖,也就是说第𝑖个同学要吃𝑎**𝑖份饭才能吃饱,当一位同学吃饱后,他就会立刻离开食堂,不会排在队伍的末尾。食堂阿姨想知道,在打完k份饭之后,队伍的样子是怎样的,但是食堂阿姨数学不太好,想让你帮忙想想办法。

输入格式

第一行给出两个整数𝑛𝑘

第二行给出𝑛个整数𝑎1,𝑎2,......𝑎**𝑛

输出格式

如果食堂阿姨打饭数少于k,请输出"-1"。

否则按照队伍顺序输出每一个同学的编号。

样例输入1

3 3

1 2 1

样例输出1

2

样例输入2

4 10

3 3 2 1

样例输出2

-1

样例输入3

7 10

1 3 3 1 2 3 1

样例输出3

6 2 3

数据规模

数据保证1≤𝑛≤10^5, 0≤𝑘≤10^14, 1≤𝑎**𝑖≤10^9。

解题思路:

一开始本蒟蒻用了队列,对每一次操作进行处理,结果可想而知,TEL(qwq)

后来经过思索,发现可以先求出一共能打多少次完整的饭,打完完整的饭后,只要对剩余的同学进行剩余次数的打饭操作即可

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=2e5+5;

long long n,k;

long long a[maxn],c[maxn];

long long cal(int x);

int main()

{

cin>>n>>k;

for(int i=1; i<=n; i++) cin>>a[i];

long long s=0;

for(int i=1; i<=n; i++) s+=a[i];

if(s<k){

cout<<"-1";

return 0;

}//如果打饭次数大于总饭数,则输出"-1"

long long l=0,r=2e9+5,mid;

while(l+1<r){

mid=(l+r)/2;

if(cal(mid)<=k) l=mid;

else r=mid;

}//用二分法找出一共能打几次完整的饭

//cout<<l<<endl;

k-=cal(l);//剩余打饭次数

int t=0;

for(int i=1; i<=n; i++){

if(a[i]>l) c[++t]=i;

}//记录剩余同学的编号

for(int i=k+1; i<=t; i++){

cout<<c[i]<<" ";

}

for(int i=1; i<=k; i++){

if(a[c[i]]-(l+1)>0) cout<<c[i]<<" ";

}

return 0;

}

long long cal(int x)

{

long long res=0;

for(int i=1; i<=n; i++){

if(a[i]>x){

res+=x;

}else{

res+=a[i];

}

}

return res;

}

任务分配


你有𝑛个任务,其中第𝑖个任务,在𝑠**𝑖开始,𝑒**𝑖时刻结束,如果做这个任务,你能获得𝑤**𝑖的收益。

但是你在一个时刻只能做一个任务,问选择哪些任务,能让你的收益尽量大。

注意:你在上一个任务结束后马上开始下一个任务是可以的。

输入格式

第一行一个整数𝑛

接下来𝑛行,每行三个整数𝑠**𝑖,𝑒**𝑖,𝑤**𝑖

输出格式

一个数,表示答案。

样例输入

3

1 3 100

2 4 199

3 5 100

样例输出

200

数据规模

对于所有数据,保证1≤𝑛≤10^3,1≤𝑠**𝑖<𝑒**𝑖≤10^3,1≤𝑤**𝑖≤10^5。

解题思路:

dp

f[i] 表示总收益,i表示目前时间是多少

完整代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=1e5+5;

long long n,s[maxn],e[maxn],w[maxn],f[maxn];

int main()

{

cin>>n;

for(int i=1; i<=n; i++) cin>>s[i]>>e[i]>>w[i];

for(int i=1; i<=1000; i++){

f[i]=max(f[i],f[i-1]);//选第i时刻不休息和休息

for(int j=1; j<=n; j++){

if(s[j]==i){

f[e[j]]=max(f[e[j]],f[i]+w[j]);

}

}//对不休息时的更新

}

cout<<f[1000];

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值