代码源Div2 101-201

101 特殊的正方形

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

输入格式

一行,一个整数n。

输出格式

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

样例输入

10

样例输出

++++++++++
+........+
+.++++++.+
+.+....+.+
+.+.++.+.+
+.+.++.+.+
+.+....+.+
+.++++++.+
+........+
++++++++++

数据范围

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

做题思路:

        按规律将 . 和 + 填入数组中,最后输出即可。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
char m[110][110];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			m[i][j]='+';
	for(int i=1;i<=(n+1)/2;++i)
	{
		for(int j=1;j<=i;++j)
		{
			if(j%2==0) m[i][j]=m[i][n-j+1]='.';
		}
		for(int j=i+1;j<=n-i;++j)
			if(i%2==0) m[i][j]='.';
	}

	for(int i=1;i<=(n+1)/2;++i)
	{
		for(int j=1;j<=n;++j)
			printf("%c",m[i][j]);
		printf("\n");
	}
	for(int i=1;i<=(n)/2;++i)
	{
		for(int j=1;j<=n;++j)
			printf("%c",m[n/2-i+1][j]);
		printf("\n");
	}
	return 0;
}

 102 走楼梯2

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

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

输入格式

一行,一个数字,表示n。

输出格式

输出走楼梯的方式总数。

样例输入

6

样例输出

12

数据规模

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

思路:

        动态规划题。f[i][j]表示已经连续走了j个一步二阶到第i阶有几种方法,且0<=j<=2。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long int
ll f[60][5];
int main()
{
	int n;
	scanf("%d",&n);
	f[1][0]=1;f[2][1]=1;
	for(int i=1;i<=n;++i)
	{
		f[i][0]+=f[i-1][0]+f[i-1][1]+f[i-1][2];
		f[i][1]+=f[i-2][0];
		f[i][2]+=f[i-2][1];
	}
	ll ans=f[n][0]+f[n][1]+f[n][2];
	printf("%lld",ans);
	return 0;
}

103 走路

有一条很长的数轴,一开始你在0的位置。接下来你要走n步,第i步你可以往右走ai或者bi。

问n步之后,0到m的每个位置,能不能走到?

输入格式

第一行,两个整数n,m。

接下来n行,每行两个整数ai,bi。

输出格式

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

输入样例

3 10
1 2
2 6
3 3

输出样例

00000011001

数据规模

对于所有数据,保证1≤n≤100,1≤m≤105,1≤ai,bi≤1000。

 思路:

        动态规划。

        f[i][j]=1表示走了i 步,j 位置能走到;=0表示不能走到。

        结果只用输出最后一次到达的位置。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int a[110],b[110];
int f[110][100010];//[i步][j能否走到] 
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)
	{
		scanf("%d%d",&a[i],&b[i]);
	}
	f[0][0]=1;
	//f[1][a[0]]=f[1][b[0]]=1;
	for(int i=0;i<n;++i)
	{
		for(int j=0;j<=m;++j)
		{
			if(j+a[i]<=m)
				if(f[i][j]) f[i+1][j+a[i]]=1;
			if(j+b[i]<=m)
				if(f[i][j]) f[i+1][j+b[i]]=1;
			f[i][j]=0;
		}
	}
	for(int i=0;i<=m;++i)
	{
		printf("%d",f[n][i]);
	}
	return 0;
}

104 简单分数统计

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

已知每个题目的分数,

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

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

输入格式

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

接下来 N 行 第 i 行输入为第 i 个人的id,

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

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

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

所有输入的字符串长度 length 满足 0<length≤500。

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

输出格式

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

样例输入

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 拿到 300 分。

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

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

思路:

        用两个结构体分别记录名字、得分和题目、分值。

在提交记录中找到对应的名字和题目,分值相加得出分数。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct id
{
	string nam;
	int sc;
}a[300];
struct ti
{
	string s;
	int fen;
}b[300];
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;++i)
	{
		cin>>a[i].nam;
	}
	for(int i=1;i<=m;++i)
	{
		cin>>b[i].s;
		scanf("%d",&b[i].fen);
	}
	for(int i=1;i<=k;++i)
	{
		string r,t,l;
		cin>>r>>t>>l;
		if(l=="WA") continue; 
		for(int j=1;j<=n;++j)
		{
			if(a[j].nam==r)
			{
				for(int q=1;q<=m;++q)
				{
					if(b[q].s==t)
					{
						a[j].sc+=b[q].fen;
					}
				}
			}
		}
	}
	for(int i=1;i<=n;++i)
	{
		cout<<a[i].nam;
		printf(" %d\n",a[i].sc);
	}
	return 0;
}

105 Alice的德州扑克

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

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

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

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

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

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

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

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

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

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

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

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

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

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

输入格式

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

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

点数和对应输入的数字:

  • 2−10 对应 2 - 10
  • J(Jack) 对应 11
  • Q(Queen) 对应 12
  • K(King) 对应 13
  • A(Ace) 对应 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<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[10];
int b[10];
int sum[10];
int aa[30];
int ans;
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	for(int j=1;j<=5;++j) scanf("%d",&a[j]);
	for(int j=1;j<=5;++j) scanf("%d",&b[j]);
	int k1=1,k2=0;
	for(int i=1;i<5;++i) 
	{
		if(a[i]+1!=a[i+1]) k1=0;
	}//k1==1顺子
	for(int i=1;i<=5;++i) aa[a[i]]++;
	sort(aa+1,aa+15+1,cmp);
	for(int i=1;i<=5;++i)
	{
		sum[b[i]]++;
	}//sum[1]==5同色 
	sort(sum+1,sum+4+1,cmp);
	if(k1&&sum[1]==5)//顺子 
	{
		if(a[5]==14) ans=1;
		else ans=2;
	}
	else if(aa[1]==4) ans=3;
	else if(aa[1]==3&&aa[2]==2) ans=4;
	else if(sum[1]==5) ans=5;
	else if(k1) ans=6;
	else ans=7;
	switch(ans)
	{
		case 1:printf("ROYAL FLUSH");break;
		case 2:printf("STRAIGHT FLUSH");break;
		case 3:printf("FOUR OF A KIND");break;
		case 4:printf("FULL HOUSE");break;
		case 5:printf("FLUSH");break;
		case 6:printf("STRAIGHT");break;
		case 7:printf("FOLD");break;
	}
	return 0;
}

106 订单编号

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

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

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

输入格式

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

第二行输入 N 个数 ai (1≤ai≤109) 作为原订单编号。

输出格式

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

样例输入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

思路:

        由于数据较大,我们可以将没有用过的编号变成区间储存。

        对于一个新编号a:

        1. 存在[ l , r ] 区间包含a,表示a还未用过。直接输出a编号,将[ l , r ]区间变为[ l , a-1]和 [ a+1,r ]两部分。如果区间左端大于区间区间右端,表示区间不存在。

        2. a不在任何一个区间中,表示a已经被占用。题中要求找到最小的大于a的还未被占用的编号,我们只需找到大于a的下一个区间,取区间的左端为编号值输出,再删除区间左端即可。同样的,如果区间左端大于区间区间右端,表示区间不存在。

        可以用set加二元组来表示区间。

        set有自动排序功能,lower_bound也可快速定位,找到大于等于a的值,但set+pair是以pair的第一个关键字优先排序的。区间左端点与a的大小关系并不确定,但区间右端一定大于等于a。因此我们可以将区间右端设为第一个关键字,比较区间左端与a的大小来判断是第一种或第二种情况。

 代码:

#include<bits/stdc++.h>
using namespace std;
set<pair<int,int> > l;
void myinsert(int a,int b)//fir,sec
{
    if(a<b) return;
    //区间后小于前,区间消失 
    l.insert({a,b});
}
int main()
{
	int n;
	scanf("%d",&n);
	l.insert({2e9,1});
    //{区间右端点,区间左端点}
	//区间里的都是没用过的 
	for(int i=1;i<=n;++i)
	{
		int a;
		scanf("%d",&a);
		auto it=l.lower_bound({a,0});
		//右端点大于等于的a位置 
		if(it->second<=a)
		//包含在区间里,没用过 
		{
			printf("%d ",a);
			myinsert(a-1,it->second);
			myinsert(it->first,a+1);
			l.erase(it);
			//一段区间分割为两段 
		}
		else//用过 
		{
			printf("%d ",it->second);
			//大于a的区间最小值 
			myinsert(it->first,it->second+1); 
			l.erase(it);
		}
	}
	
	return 0;
}

107 饿饿 饭饭

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

输入格式

第一行给出两个整数n,k。

第二行给出n个整数a1,a2,......an。

输出格式

如果食堂阿姨打饭数少于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≤n≤105, 0≤k≤1014, 1≤ai≤109。

思路:模拟。

        将每个人的饭量按从小到大排序。

        1. 如果k大于目前饭量最少的人的饭量(s)*目前人数(num),那么这个饭量最少的人一定能吃完(num-1),后面所有人也吃了s份饭,打饭次数k-=s*sum。

        2. k已经不够打完一个人时(k<num*s),则还能打k/num轮饭,还剩k%num次打饭。

        3.最后k<num时,直接模拟即可。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long int
struct node
{
	ll a;
	int l;
}p[100010];
bool cmp(node a,node b)
{
	return a.a<b.a;
}
bool cmp1(node a,node b)
{
	return a.l<b.l;
}
int main()
{
	int n;ll k;
	ll sum=0;
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&p[i].a);p[i].l=i;
		sum+=p[i].a;
	}
	
	if (sum < k)
	{
		cout << -1 << endl;
		return 0;
	}
	
	int num=n;//目前人数
	ll t=1,top=0;//top:每人已经喂了多少饭 
	sort(p+1,p+n+1,cmp);
	while(k>=(p[t].a-top)*num)
	//p[t].a-top表示清除此人还要多少饭 
	{
		k-=(p[t].a-top)*num;
		top=p[t].a;
		++t;num--;//清人 
	}
	k%=num;top+=k/num;
	//此时k<num<=n 
	sort(p+1,p+n+1,cmp1);
	for(int i=1;i<=n;++i) p[i].a-=top;

	t=0;
	for(int i=1;i<=n;++i)
	{
		if(k&&p[i].a>=1)
		{
			--k;p[i].a--;t=i;
		}
		else if(k==0&&p[i].a>0)
		{
			printf("%d ",p[i].l);
		}
	}
	
	for(int i=1;i<=t;++i)
		if(p[i].a>0)
			printf("%d ",p[i].l);

	return 0;
}

201 任务分配

你有n个任务,其中第i个任务,在si开始,ei时刻结束,如果做这个任务,你能获得wi的收益。

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

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

输入格式

第一行一个整数n。

接下来n行,每行三个整数si,ei,wi。

输出格式

一个数,表示答案。

样例输入

3
1 3 100
2 4 199
3 5 100

样例输出

200

数据规模

对于所有数据,保证1≤n≤1e3,1≤si<ei≤1e3,1≤wi≤1e5。

思路:动态规划。

        f [ i ]表示以 i 为结束时间时最大的收益。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int f[1010];//结束时间 
int a[1010],b[1010],w[1010];
int main()
{
	int n;scanf("%d",&n);
	int m=0;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&a[i],&b[i],&w[i]);
		m=max(m,b[i]);//最大结束时间 
	}
	for(int i=1;i<=m;++i)
	{
		f[i+1]=max(f[i+1],f[i]);
		//继承 
		for(int j=1;j<=n;++j)
		{
			if(i==a[j])//开始时间 可以选
			{
				f[b[j]]=max(f[b[j]],f[i]+w[j]);
			}
		}
	}
	printf("%d",f[m]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值