AtCoder Beginner Contest 358

A - Welcome to AtCoder Land

题目大意:输入S,T。当S= AtCoder and T= Land.时输出“Yes"反之”No"

分析:签到题

代码:

#include <iostream>
using namespace std;

int  main() {
	string str1, str2;
	cin >> str1 >> str2;
	if (str1 == "AtCoder" && str2 == "Land") {
		cout << "Yes";
	}
	else {
		cout << "No" << endl;
	}
}

B - Ticket Counter

题目大意:一群人买票,买票要m秒,一个人买完下一个人直接上,输入游客到达买票的时间,求每个人完成买票的时间

分析:设一个最后时间指上一个人完成买票的时间,如果这个人到达时间x大于等于上一个人完成买票时间last_time,则输出x+m反之输出last_time+m。

代码:

#include <iostream>

using namespace std;

int main() {
	int n, m;
	cin >> n >> m;
	int last_time = 0;
	for (int i=0;i<n;i++){
		int x;
		cin >> x;
		if (x >= last_time) {
			cout << x + m << endl;
			last_time = x + m;
		}
		else {
			cout << last_time + m << endl;
			last_time = last_time + m;
		}
	}
	return 0;
}

C - Popcorn

题目大意: N 个爆米花摊位,M 种不同口味的爆米花,但并不是每个摊位都出售所有口味的爆米花。

Si​ 的 j 个字符是 "o",则表示 𝑖 摊位出售 𝑗 口味的爆米花。如果是 "x",则表示 i 摊位不出售 j 口味的爆米花。每个摊位至少出售一种口味的爆米花,每种口味的爆米花至少在一个摊位出售。

高桥想尝遍所有口味的爆米花,但又不想走动太多。求高桥至少要去多少个摊位才能买到所有口味的爆米花?

分析: 一种状态dp,因为数据小,所以可以直接把每种情况罗列出来,比如我要1,2,3摊位,不要4就是1110,这样子就好了

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int n, m;
long long s[50];

int main()
{
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            char tmp;
            cin >> tmp;
            if (tmp == 'o') {
                s[i] += (1<<j);
            }
        }
    }
    int ans=n;
    for (int i=0;i<(1<<n);i++){
        int sum=0,cnt=0;
        for (int j=0;j<n;j++){
            if (i >> j & 1){
                cnt++;
                sum |= s[j];
            }
        }
        if (sum == (1<<m)-1){
            ans=min(ans,cnt);
        }
    }
    cout << ans;
}

还可以用dfs

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

const int N=1e5+10;

int n,m;
int mn=1e9;
ll a[N];
bool st[N];

void dfs(int u){
	if (u==n){
		int res=0;
		int cnt=0;
		for (int i=0;i<n;i++){
			if (st[i]==1){
				cnt++;
				res|=a[i];
			}
		}
		if (res==(1<<m)-1){
			mn=min(mn,cnt);
		}
		return;
	}
	else{
		st[u]=1;
		dfs(u+1);
		st[u]=0;
		dfs(u+1);
	}
}

int main (){
	cin >> n >> m;
	for (int i=0;i<n;i++){
		int res=0;
		for (int j=m-1;j>=0;j--){
			char x;
			cin >> x;
			if (x=='o'){
				res+=(1<<j);
			}
		}
		a[i]=res;
	}
	dfs(0);
	cout << mn << endl;
	return 0;
}

D - Souvenirs

题目大意:N个 盒子。盒子 𝑖 的价格为 𝐴𝑖日元,里面有 𝐴𝑖块糖果。 N 个盒子中买 𝑀个,然后给 𝑀 个叫 1,2,…,𝑀的人每人一盒。在这里,他想买的盒子要满足以下条件:

  • 对于每个 𝑖=1,2,…,𝑀 人, 𝑖i都会得到一个至少装有 𝐵𝑖块糖果的盒子。

不允许给一个人多个盒子,也不允许给多个人同一个盒子。

求是否可能买到满足条件的 M 盒,如果可能,求需要支付的最小总金额

分析:贪心,直接在A中找大于等于B的数,如果没有就是不能。

代码:

#include <iostream>
#include <set>
using namespace std;

multiset<int> A;

int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 0; i < n; i++) {
		int tmp;
		cin >> tmp;
		A.insert(tmp);
	}
	long long sum = 0;
	for (int i = 0; i < m; i++) {
		int tmp;
		cin >> tmp;
		if (A.lower_bound(tmp) == A.end()) {
			cout << -1 << endl;
			return 0;
		}
		sum += *A.lower_bound(tmp);
		A.erase(A.lower_bound(tmp));
	}
	cout << sum << endl;
	return 0;
}

E - Alphabet Tiles

题目大意:长度在 1和n(含)之间的由大写英文字母组成的字符串中,满足以下条件的字符串的个数(模为 998244353998244353 ):

  • 对于满足 1≤𝑖≤26的每个整数 𝑖,下面的条件成立:
    • 设 𝑎𝑖​ 是按词典顺序排列的 𝑖 个大写英文字母。
    • 字符串中 𝑎𝑖 的出现次数介于 0 和 𝐶𝑖 之间(包括首尾两次)。

分析:dp[i][j]指的用前i个字母组成的长度为j的字符串的个数,最后dp[26][1],dp[26][2]....dp[26][n]加起来就好了,dp[i][j]=dp[i-1][j-k]*C[j][k];C是组合数提前预处理一下就好了

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

const int N=1010;
const ll p=998244353;
ll C[N][N];
ll dp[N][N];
int c[N];
int n;

void init()
{
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j <= i; j ++ )
            if (!j) C[i][j] = 1;
            else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % p;
}

int main (){
	cin >> n;
	init();
	for (int i=1;i<=26;i++) cin >> c[i];
	dp[0][0]=1;
	for (int i=1;i<=26;i++) {
		for (int j=0;j<=n;j++){
			for (int k=0;k<=min(j,c[i]);k++){
				dp[i][j]+=dp[i-1][j-k]*C[j][k];
				dp[i][j]%=p;
			}
		} 
	}
	ll res=0;
	for (int i=1;i<=n;i++){
		res+=dp[26][i];
		res%=p;
	}
	cout << res << endl;
	return 0;
}

F - Easiest Maze

题目大意:点击跳转题目 因为很长

分析:因为答案可以有很多(可以虚空造墙),我们先做map的基础,由‘+’,‘-’,‘|',‘.'组成,为什么会有墙呢,因为我们提前把墙造好了,到时候遍历路径的时候,直接开路,改变一下路就好了 ,然后对于中间的处理用4 4 14 模拟一遍就可以很好的了解了,最关键的是最后一行的处理,可以用 5 5 23 模拟一遍就好了。(代码是借鉴了榜一大佬的代码,看代码理解的题)(博客只是记录一下)

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

const int N=220;

char map[N][N];

int main (){
	int n,m,k;
	cin >> n >> m >> k;
	if (k-n<0 || (k-n)%2==1){
		cout << "No" << endl;
	}
	else{
		cout << "Yes" << endl;
		
		memset(map,'+',N*N);
		
		for (int i=1;i<2*n;i++){
			if (i%2==1){
				for (int j=1;j<2*m;j++){
					if (j%2==1) map[i][j]='o';
					else map[i][j]='|';
				}
			}
			else{
				for (int j=1;j<2*m;j++){
					if (j%2==1) map[i][j]='-';
					else map[i][j]='+';
				}
				map[i][m * 2 - 1] = '.';
			}
		}
		map[0][m*2-1]='S';
		map[n*2][m*2-1]='G';
		int cnt=k-n;
		//对中间行的处理
		for (int i = 1; i < n * 2 - 2; i += 4){
      		for (int j = m * 2 - 1; j >= 3; j -= 2){
        		if (cnt > 0){
          			map[i + 1][j] = '-';
          			map[i][j - 1] = '.';
          			map[i + 2][j - 1] = '.';
          			map[i + 1][j - 2] = '.';
          			cnt -= 2;
        		}
      		}
    	}
    	//对最后一行的处理
		for (int j = 1; j <= m * 2 - 5; j += 4){
      		if (cnt > 0){
        	map[n * 2 - 3][j + 1] = '|';
        	map[n * 2 - 2][j] = '.';
        	map[n * 2 - 2][j + 2] = '.';
        	map[n * 2 - 1][j + 1] = '.';
        	cnt -= 2;
      		}
    	}
		for (int i=0;i<2*n+1;i++){
			for (int j=0;j<2*m+1;j++){
				cout << map[i][j];
			}
			cout << endl;
		}
	}
	return 0;
}

G - AtCoder Tour

题目大意:网格中有 𝐻 行和 𝑊 列。让 (𝑖,𝑗) 表示第 𝑖 行和第 𝑗 列的单元格。

高桥从 (𝑆𝑖,𝑆𝑗)单元格开始,重复以下操作 𝐾 次:

  • 他要么停留在当前单元格,要么移动到相邻单元格。在这个操作之后,如果他在 (𝑖,𝑗) 单元格中,他将获得 𝐴𝑖,𝑗​ 的趣味值。

求最大趣味值。

分析:dp[k][i][j]指的是k步时在(i,j)坐标上的最大趣味值,dp[k][i][j]是从dp[k-1][x][y],(x,y)是上一步的坐标就是5个位置,k的范围是1e9但是实际上最多2500就能到最大的Aij。所以我们最后乘一下自己本身坐标的值和k与步数的差值就行了。

代码:

#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <cmath>

using namespace std;

typedef long long ll;
typedef pair<int,int> PII;

const ll inf=1e18;
const int N=60;

int n,m,k;
int stx,sty;
int x,y;
ll w[N][N];
ll dp[N][N][2510],ans;
int dx[5]={0,1,0,-1,0},dy[5]={-1,0,1,0,0};

int main (){
	cin >> n >> m >> k;
	cin >> stx >> sty;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			cin >> w[i][j];
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			for(int t=0;t<=2500&&t<=k;t++)dp[i][j][t]=-inf;
		}
	}
	dp[stx][sty][0]=0;
	for (int t=0;t<2500 && t<k;t++){
		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				for(int c=0;c<5;c++){
					x=i+dx[c];
					y=j+dy[c];
					if(x<1||x>n)continue;
					if(y<1||y>m)continue;
					dp[x][y][t+1]=max(dp[x][y][t+1],dp[i][j][t]+w[x][y]);
				}
			}	
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			for(int t=0;t<=2500&&t<=k;t++) ans=max(ans,dp[i][j][t]+w[i][j]*(k-t));
		}
	}
	cout << ans << endl;
	return 0;
}

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值